├── .github ├── FUNDING.yml └── workflows │ └── main.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── cvtasm.pl ├── lib2ine.c ├── lib2ine.h ├── libSDL2-2.0.so.0 ├── lx_dump.c ├── lx_loader.c ├── lxapigen.pl ├── native ├── doscalls-lx.h ├── doscalls.c ├── doscalls.h ├── kbdcalls-lx.h ├── kbdcalls.c ├── kbdcalls.h ├── mdm.c ├── mdm.h ├── msg-lx.h ├── msg.c ├── msg.h ├── nls-lx.h ├── nls.c ├── nls.h ├── os2.h ├── os2errors.h ├── os2native.h ├── os2native16.h ├── os2types.h ├── pmgpi-lx.h ├── pmgpi.c ├── pmgpi.h ├── pmmerge.c ├── pmmerge.h ├── pmshapi.c ├── pmshapi.h ├── pmwin-lx.h ├── pmwin.c ├── pmwin.h ├── quecalls-lx.h ├── quecalls.c ├── quecalls.h ├── sesmgr-lx.h ├── sesmgr.c ├── sesmgr.h ├── som.c ├── som.h ├── tcpip32-lx.h ├── tcpip32.c ├── tcpip32.h ├── viocalls-lx.h ├── viocalls.c └── viocalls.h ├── os2imports.pl ├── research ├── 1996-10-09_Rel_10_IBM_OS2_16-32-BIT_OBJECT_MODULE_FORMAT_(OMF)_AND_LINEAR_EXECUTABLE_MODULE_FORMAT_(LX)-lx386.pdf ├── The Effect of Compression on Performance in a Demand Paging System.pdf ├── ldt.c ├── lxexe.txt └── neexe.txt ├── tests ├── emx.dll ├── hello.asm ├── hello.c ├── hello.exe ├── hello16.c ├── hello16.exe ├── helloc.exe ├── testargv.c ├── testargv.exe ├── testargv16.exe ├── testbeep.c ├── testbeep.exe ├── testpm.c ├── testpm.exe ├── testtls.c └── testtls.exe └── unimplemented.pl /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [icculus] 2 | patreon: icculus 3 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | Build: 7 | name: ${{ matrix.platform.name }} 8 | runs-on: ${{ matrix.platform.os }} 9 | strategy: 10 | matrix: 11 | platform: 12 | - { name: Linux, os: ubuntu-20.04, flags: -GNinja } 13 | #- { name: Windows, os: windows-latest } 14 | #- { name: MacOS, os: macos-latest } 15 | steps: 16 | - name: Setup Linux dependencies 17 | if: runner.os == 'Linux' 18 | run: | 19 | sudo apt-get update 20 | sudo apt-get install cmake ninja-build libncursesw5-dev libncursesw5:i386 libsdl2-dev 21 | - name: Get 2ine sources 22 | uses: actions/checkout@v2 23 | - name: Configure CMake 24 | run: cmake -B build ${{ matrix.platform.flags }} 25 | - name: Build 26 | run: cmake --build build/ 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | cmake-* 2 | 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4) 2 | project(2ine) 3 | 4 | # Note that this project doesn't work on Mac OS X because I can't mmap() 5 | # address 0x10000, which is the usual base address for OS/2 binaries. 6 | # It appears the address is already accessible when main() begins, but no 7 | # objects seem to be loaded there. I don't know what it is...maybe some 8 | # thing allocated by the C runtime at startup? Have to solve that somehow or 9 | # give up on Mac support. 10 | # 11 | # Eventually, even on Linux, it might make sense to override malloc and friends 12 | # at the dynamic loader level, so we control all allocations even if they 13 | # happen in glibc. Once we have that, make sure they all sit in the upper 14 | # 2 gigabytes (reserved for system use on OS/2, so this works out), probably 15 | # with them mmap()'d there via a local copy of dlmalloc or something. 16 | # 17 | # Note that 32-bit OS/2 programs only got 512 megabytes of the address space 18 | # (enormous in the days of machines with a couple megabytes of physical RAM!) 19 | # to accomodate thunking to and from 16 bit code. We don't bother with this 20 | # at the moment, though, but maybe we must at some point. I hope not. 21 | # 22 | # Also, it might be nice if we can run as a 64-bit process and thunk around in 23 | # 32-bits as necessary, but I don't know the technical barriers to this yet. 24 | # If we can pull that off, it would allow an OS/2 app to have the full 4 25 | # gigabytes of memory, and we'll just put 2ine's data outside of that range, 26 | # and run the native bits with more registers, etc. Maybe even keep the 27 | # native functions out of low memory and only eat a few bytes of it with 28 | # trampolines. I'm probably getting ahead of myself, though, as it's not like 29 | # any OS/2 apps were _that_ memory hungry, and honestly? Port your software. 30 | 31 | if(NOT CMAKE_BUILD_TYPE) 32 | set(DEBUG_BUILD ON) 33 | endif() 34 | if(CMAKE_BUILD_TYPE STREQUAL "Debug") 35 | set(DEBUG_BUILD ON) 36 | endif() 37 | 38 | if(DEBUG_BUILD) 39 | add_definitions(-DDEBUG -O0) 40 | else() 41 | add_definitions(-D_RELEASE) 42 | add_definitions(-DNDEBUG) 43 | add_definitions(-DRELEASE) 44 | endif() 45 | 46 | option(LX_LEGACY "Enable OS/2 binary support (vs just native apps)" TRUE) 47 | if(NOT LX_LEGACY) 48 | add_definitions(-DLX_LEGACY=0) 49 | endif() 50 | 51 | add_definitions(-std=c99 -Wall -ggdb3) 52 | add_definitions(-D_FILE_OFFSET_BITS=64) 53 | 54 | set(CURSES_NEED_WIDE TRUE) 55 | set(CURSES_NEED_NCURSES TRUE) 56 | find_package(Curses) 57 | if(NOT CURSES_FOUND) 58 | message(FATAL_ERROR "ncurses not found") 59 | endif() 60 | 61 | include_directories(${CURSES_INCLUDE_DIR}) 62 | if(CURSES_HAVE_NCURSESW_NCURSES_H) 63 | add_definitions(-DHAVE_NCURSESW_NCURSES_H) 64 | elseif(CURSES_HAVE_NCURSESW_CURSES_H) 65 | add_definitions(-DHAVE_NCURSESW_CURSES_H) 66 | elseif(CURSES_HAVE_NCURSESW_H) 67 | add_definitions(-DHAVE_NCURSESW_H) 68 | elseif(CURSES_HAVE_CURSES_H) 69 | add_definitions(-DHAVE_CURSES_H) 70 | elseif(CURSES_HAVE_NCURSES_CURSES_H) 71 | add_definitions(-DHAVE_NCURSESW_NCURSES_H) 72 | endif() 73 | 74 | # !!! FIXME 75 | include_directories("/usr/local/include/SDL2") 76 | 77 | add_library(2ine SHARED "lib2ine.c") 78 | if(LX_LEGACY) 79 | set_target_properties(2ine PROPERTIES COMPILE_FLAGS "-m32") 80 | set_target_properties(2ine PROPERTIES LINK_FLAGS "-m32 -ggdb3") 81 | endif() 82 | target_link_libraries(2ine "pthread") 83 | 84 | foreach(_I doscalls;msg;nls;quecalls;viocalls;kbdcalls;sesmgr;som;pmwin;pmshapi;pmgpi;tcpip32) 85 | add_library(${_I} SHARED "native/${_I}.c") 86 | if(LX_LEGACY) 87 | set_target_properties(${_I} PROPERTIES COMPILE_FLAGS "-m32") 88 | set_target_properties(${_I} PROPERTIES LINK_FLAGS "-m32 -ggdb3") 89 | endif() 90 | target_link_libraries(${_I} 2ine) 91 | endforeach() 92 | 93 | target_link_libraries(doscalls "pthread") 94 | # FIXME target_link_libraries(viocalls ${CURSES_LIBRARIES}) 95 | target_link_libraries(viocalls /usr/lib/i386-linux-gnu/libncursesw.so.6) 96 | 97 | # !!! FIXME: clean this up/ 98 | if(LX_LEGACY) 99 | target_link_libraries(2ine "${CMAKE_CURRENT_SOURCE_DIR}/libSDL2-2.0.so.0") 100 | target_link_libraries(pmwin "${CMAKE_CURRENT_SOURCE_DIR}/libSDL2-2.0.so.0") 101 | else() 102 | target_link_libraries(2ine "SDL2") 103 | target_link_libraries(pmwin "SDL2") 104 | endif() 105 | 106 | add_executable(lx_dump lx_dump.c) 107 | 108 | if(LX_LEGACY) 109 | add_executable(lx_loader lx_loader.c) 110 | target_link_libraries(lx_loader 2ine) 111 | target_link_libraries(lx_loader "dl") 112 | set_target_properties(lx_loader PROPERTIES COMPILE_FLAGS "-m32 -no-pie") 113 | set_target_properties(lx_loader PROPERTIES LINK_FLAGS "-m32 -no-pie -ggdb3") 114 | endif() 115 | 116 | # end of CMakeLists.txt ... 117 | 118 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2022 Ryan C. Gordon . 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 2ine 2 | 3 | *What is this?* 4 | 5 | It's a program that loads and runs OS/2 .exe files on Linux. 6 | 7 | *Does it work?* 8 | 9 | Barely. It runs some command line OS/2 apps. 10 | 11 | *Why?* 12 | 13 | Because. 14 | 15 | *Does it work on Mac OS X?* 16 | 17 | No. 18 | 19 | *I have questions.* 20 | 21 | I have answers: icculus@icculus.org 22 | 23 | --ryan. 24 | 25 | -------------------------------------------------------------------------------- /cvtasm.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # 3 | # 2ine; an OS/2 emulator for Linux. 4 | # 5 | # Please see the file LICENSE.txt in the source's root directory. 6 | # 7 | # This file written by Ryan C. Gordon. 8 | 9 | 10 | # run this on the output from ndisasm. 11 | 12 | use warnings; 13 | use strict; 14 | 15 | while (<>) { 16 | chomp; 17 | my ($bytes, $asm) = /\A.*?\s+(.*?)\s+(.*)\Z/; 18 | my $first = 1; 19 | while ($bytes ne '') { 20 | $bytes =~ s/\A(..)//; 21 | my $hex = $1; 22 | if ($first and ($bytes eq '')) { 23 | print(" *(ptr++) = 0x$hex; /* $asm */\n"); 24 | } elsif ($first) { 25 | print(" *(ptr++) = 0x$hex; /* $asm... */\n"); 26 | } else { 27 | print(" *(ptr++) = 0x$hex; /* ...$asm */\n"); 28 | } 29 | $first = 0; 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /lib2ine.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | /* lib2ine is support code and data that is common between various native 10 | reimplementations of the OS/2 API, and the OS/2 binary loader. */ 11 | 12 | #ifndef _INCL_LIB2INE_H_ 13 | #define _INCL_LIB2INE_H_ 1 14 | 15 | #ifndef _GNU_SOURCE 16 | #define _GNU_SOURCE 17 | #endif 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | typedef uint8_t uint8; 25 | typedef uint16_t uint16; 26 | typedef uint32_t uint32; 27 | typedef uint64_t uint64; 28 | 29 | typedef int8_t sint8; 30 | typedef int16_t sint16; 31 | typedef int32_t sint32; 32 | typedef int64_t sint64; 33 | 34 | typedef unsigned int uint; 35 | 36 | #ifndef _STUBBED 37 | #define _STUBBED(x, what) do { \ 38 | static int seen_this = 0; \ 39 | if (!seen_this) { \ 40 | seen_this = 1; \ 41 | fprintf(stderr, "2INE " what ": %s at %s (%s:%d)\n", x, __FUNCTION__, __FILE__, __LINE__); \ 42 | } \ 43 | } while (0) 44 | #endif 45 | 46 | #if 0 47 | #ifndef STUBBED 48 | #define STUBBED(x) _STUBBED(x, "STUBBED") 49 | #endif 50 | #ifndef FIXME 51 | #define FIXME(x) _STUBBED(x, "FIXME") 52 | #endif 53 | #endif 54 | 55 | #ifndef STUBBED 56 | #define STUBBED(x) do {} while (0) 57 | #endif 58 | #ifndef FIXME 59 | #define FIXME(x) do {} while (0) 60 | #endif 61 | 62 | #pragma pack(push, 1) 63 | typedef struct LxHeader 64 | { 65 | uint8 magic_l; 66 | uint8 magic_x; 67 | uint8 byte_order; 68 | uint8 word_order; 69 | uint32 lx_version; 70 | uint16 cpu_type; 71 | uint16 os_type; 72 | uint32 module_version; 73 | uint32 module_flags; 74 | uint32 module_num_pages; 75 | uint32 eip_object; 76 | uint32 eip; 77 | uint32 esp_object; 78 | uint32 esp; 79 | uint32 page_size; 80 | uint32 page_offset_shift; 81 | uint32 fixup_section_size; 82 | uint32 fixup_section_checksum; 83 | uint32 loader_section_size; 84 | uint32 loader_section_checksum; 85 | uint32 object_table_offset; 86 | uint32 module_num_objects; 87 | uint32 object_page_table_offset; 88 | uint32 object_iter_pages_offset; 89 | uint32 resource_table_offset; 90 | uint32 num_resource_table_entries; 91 | uint32 resident_name_table_offset; 92 | uint32 entry_table_offset; 93 | uint32 module_directives_offset; 94 | uint32 num_module_directives; 95 | uint32 fixup_page_table_offset; 96 | uint32 fixup_record_table_offset; 97 | uint32 import_module_table_offset; 98 | uint32 num_import_mod_entries; 99 | uint32 import_proc_table_offset; 100 | uint32 per_page_checksum_offset; 101 | uint32 data_pages_offset; 102 | uint32 num_preload_pages; 103 | uint32 non_resident_name_table_offset; 104 | uint32 non_resident_name_table_len; 105 | uint32 non_resident_name_table_checksum; 106 | uint32 auto_ds_object_num; 107 | uint32 debug_info_offset; 108 | uint32 debug_info_len; 109 | uint32 num_instance_preload; 110 | uint32 num_instance_demand; 111 | uint32 heapsize; 112 | } LxHeader; 113 | 114 | typedef struct LxObjectTableEntry 115 | { 116 | uint32 virtual_size; 117 | uint32 reloc_base_addr; 118 | uint32 object_flags; 119 | uint32 page_table_index; 120 | uint32 num_page_table_entries; 121 | uint32 reserved; 122 | } LxObjectTableEntry; 123 | 124 | typedef struct LxObjectPageTableEntry 125 | { 126 | uint32 page_data_offset; 127 | uint16 data_size; 128 | uint16 flags; 129 | } LxObjectPageTableEntry; 130 | 131 | typedef struct LxResourceTableEntry 132 | { 133 | uint16 type_id; 134 | uint16 name_id; 135 | uint32 resource_size; 136 | uint16 object; 137 | uint32 offset; 138 | } LxResourceTableEntry; 139 | 140 | typedef struct NeHeader 141 | { 142 | uint8 magic_n; 143 | uint8 magic_e; 144 | uint8 linker_version; 145 | uint8 linker_revision; 146 | uint16 entry_table_offset; 147 | uint16 entry_table_size; 148 | uint32 crc32; 149 | uint16 module_flags; 150 | uint16 auto_data_segment; 151 | uint16 dynamic_heap_size; 152 | uint16 stack_size; 153 | uint16 reg_ip; 154 | uint16 reg_cs; 155 | uint16 reg_sp; 156 | uint16 reg_ss; 157 | uint16 num_segment_table_entries; 158 | uint16 num_module_ref_table_entries; 159 | uint16 non_resident_name_table_size; 160 | uint16 segment_table_offset; 161 | uint16 resource_table_offset; 162 | uint16 resident_name_table_offset; 163 | uint16 module_reference_table_offset; 164 | uint16 imported_names_table_offset; 165 | uint32 non_resident_name_table_offset; 166 | uint16 num_movable_entries; 167 | uint16 sector_alignment_shift_count; 168 | uint16 num_resource_entries; 169 | uint8 exe_type; 170 | uint8 os2_exe_flags; 171 | uint8 reserved[8]; 172 | } NeHeader; 173 | 174 | typedef struct NeSegmentTableEntry 175 | { 176 | uint16 offset; 177 | uint16 size; 178 | uint16 segment_flags; 179 | uint16 minimum_allocation; 180 | } NeSegmentTableEntry; 181 | 182 | #pragma pack(pop) 183 | 184 | 185 | typedef struct LxMmaps 186 | { 187 | void *mapped; 188 | void *addr; 189 | size_t size; 190 | int prot; 191 | uint16 alias; // 16:16 alias, if one. 192 | } LxMmaps; 193 | 194 | typedef struct LxExport 195 | { 196 | uint32 ordinal; 197 | const char *name; // can be NULL 198 | void *addr; 199 | const LxMmaps *object; 200 | } LxExport; 201 | 202 | struct LxModule; 203 | typedef struct LxModule LxModule; 204 | struct LxModule 205 | { 206 | uint32 refcount; 207 | int is_lx; // 1 if an LX module, 0 if NE. 208 | union 209 | { 210 | LxHeader lx; 211 | NeHeader ne; 212 | } header; 213 | 214 | char name[256]; // !!! FIXME: allocate this. 215 | 216 | LxModule **dependencies; 217 | uint32 num_dependencies; 218 | 219 | LxMmaps *mmaps; 220 | uint32 num_mmaps; 221 | 222 | const LxExport *exports; 223 | uint32 num_exports; 224 | void *nativelib; 225 | uint32 eip; 226 | uint32 esp; 227 | uint16 autodatasize; // only used for NE binaries. 228 | int initialized; 229 | char *os2path; // absolute path to module, in OS/2 format 230 | // !!! FIXME: put this elsewhere? 231 | uint32 signal_exception_focus_count; 232 | LxModule *prev; // all loaded modules are in a doubly-linked list. 233 | LxModule *next; // all loaded modules are in a doubly-linked list. 234 | }; 235 | 236 | #pragma pack(push, 1) 237 | typedef struct LxTIB2 238 | { 239 | uint32 tib2_ultid; 240 | uint32 tib2_ulpri; 241 | uint32 tib2_version; 242 | uint16 tib2_usMCCount; 243 | uint16 tib2_fMCForceFlag; 244 | } LxTIB2; 245 | 246 | typedef struct LxTIB 247 | { 248 | void *tib_pexchain; 249 | void *tib_pstack; 250 | void *tib_pstacklimit; 251 | LxTIB2 *tib_ptib2; 252 | uint32 tib_version; 253 | uint32 tib_ordinal; 254 | } LxTIB; 255 | 256 | typedef struct LxPIB 257 | { 258 | uint32 pib_ulpid; 259 | uint32 pib_ulppid; 260 | void *pib_hmte; 261 | char *pib_pchcmd; 262 | char *pib_pchenv; 263 | uint32 pib_flstatus; 264 | uint32 pib_ultype; 265 | } LxPIB; 266 | 267 | #pragma pack(pop) 268 | 269 | // We put the 128 bytes of TLS slots (etc) after the TIB structs. 270 | typedef struct LxPostTIB 271 | { 272 | uint32 tls[32]; 273 | void *anchor_block; 274 | } LxPostTIB; 275 | 276 | // There are a few things that need access to the sound hardware: 277 | // DosBeep(), MMOS/2, DART, basic system sounds, etc. We unify all this 278 | // into a single SDL audio device open where possible, so that we don't 279 | // have to deal with multiple devices, but that means it has to move into 280 | // lib2ine so multiple libraries can access it. 281 | typedef int (*LxAudioGeneratorFn)(void *data, float *stream, int len, int freq); 282 | 283 | #define LXTIBSIZE (sizeof (LxTIB) + sizeof (LxTIB2) + sizeof (LxPostTIB)) 284 | 285 | #define LX_MAX_LDT_SLOTS 8192 286 | 287 | typedef struct LxLoaderState 288 | { 289 | LxModule *loaded_modules; 290 | LxModule *main_module; 291 | uint8 main_tibspace[LXTIBSIZE]; 292 | LxPIB pib; 293 | int using_lx_loader; 294 | int subprocess; 295 | int running; 296 | int trace_native; 297 | int trace_events; 298 | char *disks[26]; // mount points, A: through Z: ... NULL if unmounted. 299 | char *current_dir[26]; // current directory, per-disk, A: through Z: ... NULL if unmounted. 300 | int current_disk; // 1==A:\\, 2==B:\\, etc. 301 | uint32 diskmap; // 1<<0==drive A mounted, 1<<1==drive B mounted, etc. 302 | float beep_volume; 303 | uint8 main_tib_selector; 304 | uint32 mainstacksize; 305 | uint16 original_cs; 306 | uint16 original_ds; 307 | uint16 original_es; 308 | uint16 original_ss; 309 | uint32 *ldt; //[LX_MAX_LDT_SLOTS]; 310 | char *libpath; 311 | uint32 libpathlen; 312 | uint32 *tlspage; 313 | uint32 tlsmask; // one bit for each TLS slot in use. 314 | uint8 tlsallocs[32]; // number of TLS slots allocated in one block, indexed by starting block (zero if not the starting block). 315 | void (*dosExit)(uint32 action, uint32 result); 316 | void (*initOs2Tib)(uint8 *tibspace, void *_topOfStack, const size_t stacklen, const uint32 tid); 317 | uint16 (*setOs2Tib)(uint8 *tibspace); 318 | LxTIB *(*getOs2Tib)(void); 319 | void (*deinitOs2Tib)(const uint16 selector); 320 | void *(*allocSegment)(uint16 *selector, const int iscode); 321 | void (*freeSegment)(const uint16 selector); 322 | int (*findSelector)(const uint32 addr, uint16 *outselector, uint16 *outoffset, int iscode); 323 | void (*freeSelector)(const uint16 selector); 324 | void *(*convert1616to32)(const uint32 addr1616); 325 | uint32 (*convert32to1616)(void *addr32); 326 | LxModule *(*loadModule)(const char *modname); 327 | char *(*makeUnixPath)(const char *os2path, uint32 *err); 328 | void __attribute__((noreturn)) (*terminate)(const uint32 exitcode); 329 | int (*registerAudioGenerator)(LxAudioGeneratorFn fn, void *data, const int singleton); 330 | void (*lib2ine_shutdown)(void); 331 | } LxLoaderState; 332 | 333 | typedef const LxExport *(*LxNativeModuleInitEntryPoint)(uint32 *lx_num_exports); 334 | typedef void (*LxNativeModuleDeinitEntryPoint)(void); 335 | 336 | // !!! FIXME: need to change this symbol name. 337 | extern __attribute__((visibility("default"))) LxLoaderState GLoaderState; 338 | 339 | #define LX_NATIVE_CONSTRUCTOR(modname) void __attribute__((constructor)) lxNativeConstructor_##modname(void) 340 | #define LX_NATIVE_DESTRUCTOR(modname) void __attribute__((destructor)) lxNativeDestructor_##modname(void) 341 | 342 | #endif 343 | 344 | // end of lib2ine.h ... 345 | 346 | -------------------------------------------------------------------------------- /libSDL2-2.0.so.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icculus/2ine/1ca194f39b6322d5c6cc1006616ed6a62f74c193/libSDL2-2.0.so.0 -------------------------------------------------------------------------------- /lxapigen.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use warnings; 4 | use strict; 5 | use File::Basename; 6 | 7 | my %typesizes = ( 8 | 'LONG' => 4, 9 | 'ULONG' => 4, 10 | 'SHORT' => 2, 11 | 'USHORT' => 2, 12 | 'HVIO' => 2, 13 | 'HKBD' => 2, 14 | ); 15 | 16 | sub typesize { 17 | my $t = shift; 18 | return 4 if ($t =~ /\AP/); # pointers are 4 bytes (16:16). 19 | die("Unknown type '$t', please update \%typesizes\n") if not defined $typesizes{$t}; 20 | return $typesizes{$t}; 21 | } 22 | 23 | chdir(dirname(__FILE__)) or die("failed to chdir to script location: $!\n"); 24 | my $dirname = 'native'; 25 | opendir(DIRH, $dirname) or die("Failed to opendir '$dirname': $!\n"); 26 | 27 | while (readdir(DIRH)) { 28 | next if not /\.h\Z/; 29 | next if /\Aos2/; 30 | next if /\-lx\.h\Z/; 31 | 32 | my $module = $_; 33 | my $header = "$dirname/$module"; 34 | $module =~ s/\.h\Z//; 35 | open(IN, '<', $header) or die("Failed to open '$header' for reading: $!\n"); 36 | 37 | print("$module ...\n"); 38 | 39 | my %ordinalmap = (); 40 | my $has16bitfns = 0; 41 | 42 | while () { 43 | chomp; 44 | next if not /OS2APIINFO/; 45 | my $line = $_; 46 | 47 | if (/\AOS2EXPORT\s+(.*?)\s+(OS2API|OS2API16)\s+(.*?)\s*\((.*?)\)\s+OS2APIINFO\((.*?)\);/) { 48 | my %table = ( 49 | 'rettype' => $1, 50 | 'apitype' => $2, 51 | 'fn' => $3, 52 | 'args' => $4, 53 | ); 54 | my $apiinfo = $5; 55 | 56 | my $is16bit = $table{'apitype'} eq 'OS2API16'; 57 | $table{'is16bit'} = $is16bit; 58 | $has16bitfns |= $is16bit; 59 | 60 | #print("rettype='$rettype' fn='$fn' args='$args' apiinfo='$apiinfo'\n"); 61 | 62 | my $fn = $table{'fn'}; 63 | my $ordinal = undef; 64 | my $expname = undef; 65 | if ($apiinfo =~ /\A(\d+)\Z/) { 66 | $ordinal = int($1); 67 | } else { 68 | foreach (split(/,/, $apiinfo)) { 69 | #print("apiinfoarg: '$_'\n"); 70 | my ($infokey, $infoval) = /\A(.*?)\=(.*)\Z/; 71 | #print("apiinfo key='$infokey' val='$infoval'\n"); 72 | if ($infokey eq 'ord') { 73 | if ($infoval =~ /\A(\d+)\Z/) { 74 | $ordinal = int($1); 75 | } else { 76 | die("Invalid ordinal '$infoval' for '$fn'\n"); 77 | } 78 | } elsif ($infokey eq 'name') { 79 | $expname = $infoval; 80 | } else { 81 | die("unknown OS2APIINFO key '$infokey' for '$fn'\n"); 82 | } 83 | } 84 | } 85 | 86 | $table{'ordinal'} = $ordinal; 87 | $table{'expname'} = $expname if defined $expname; 88 | 89 | if (defined $ordinalmap{$ordinal}) { 90 | my $dupfn = $ordinalmap{$ordinal}{'fn'}; 91 | die("Duplicate ordinal #$ordinal between '$fn' and '$dupfn'\n"); 92 | } 93 | 94 | $ordinalmap{$ordinal} = \%table; 95 | } else { 96 | die ("Couldn't parse:\n\n $line\n\n") 97 | } 98 | } 99 | 100 | close(IN); 101 | 102 | next if (not %ordinalmap); # no exported items? 103 | 104 | #use Data::Dumper qw(Dumper); print Dumper \%ordinalmap; 105 | 106 | 107 | # Here we go... 108 | 109 | my $finalfname = "$dirname/$module-lx.h"; 110 | my $outfname = "$finalfname-new"; 111 | open(OUT, '>', $outfname) or die("Failed to open '$outfname' for writing: $!\n"); 112 | 113 | print OUT < $b } keys(%ordinalmap) ) { 129 | my $tableref = $ordinalmap{$_}; 130 | my $fn = $tableref->{'fn'}; 131 | my $argstr = $tableref->{'args'}; 132 | my $rettype = $tableref->{'rettype'}; 133 | my $is16bit = $tableref->{'is16bit'}; 134 | my @args = (); 135 | 136 | if (($argstr ne 'VOID') and ($argstr ne 'void')) { 137 | @args = split /,/, $argstr; 138 | } 139 | 140 | # Build a little wrapper that'll pull arguments off the stack and 141 | # convert to whatever the native calling conventions are. 142 | if ($is16bit) { 143 | print OUT "static $rettype bridge16to32_$fn(uint8 *args) {\n"; 144 | #foreach (@args) { 145 | # arguments are listed backwards here. 146 | for my $i (reverse 0..$#args) { 147 | my $arg = $args[$i]; 148 | my ($t, $n) = $arg =~ /\A\s*(.*?)\s+(.*?)\s*\Z/; 149 | #print("arg='$_' t='$t' n='$n'\n"); 150 | my $a = ($t =~ /\AP/) ? 'PTRARG' : 'ARG'; # it's a pointer? 151 | print OUT " LX_NATIVE_MODULE_16BIT_BRIDGE_$a($t, $n);\n"; 152 | } 153 | 154 | print OUT " "; 155 | if (($rettype ne 'void') && ($rettype ne 'VOID')) { 156 | # Currently it's reasonable to assume the retval will land in EAX. 157 | print OUT "return "; 158 | } 159 | 160 | print OUT "$fn("; 161 | my $comma = ''; 162 | foreach (@args) { 163 | my ($t, $n) = /\A\s*(.*?)\s+(.*?)\s*\Z/; 164 | print OUT "$comma$n"; 165 | $comma = ', '; 166 | } 167 | print OUT ");\n"; 168 | 169 | print OUT "}\n\n"; 170 | } 171 | } 172 | 173 | if ($has16bitfns) { 174 | print OUT "LX_NATIVE_MODULE_16BIT_SUPPORT()\n"; 175 | foreach (sort { $a <=> $b } keys(%ordinalmap) ) { 176 | my $tableref = $ordinalmap{$_}; 177 | next if not $tableref->{'is16bit'}; 178 | my $fn = $tableref->{'fn'}; 179 | print OUT " LX_NATIVE_MODULE_16BIT_API($fn)\n"; 180 | } 181 | 182 | print OUT "LX_NATIVE_MODULE_16BIT_SUPPORT_END()\n"; 183 | print OUT "\n"; 184 | print OUT "LX_NATIVE_MODULE_DEINIT({\n"; 185 | print OUT " LX_NATIVE_MODULE_DEINIT_16BIT_SUPPORT();\n"; 186 | print OUT "})\n"; 187 | print OUT "\n"; 188 | print OUT "static int init16_$module(void) {\n"; 189 | print OUT " LX_NATIVE_MODULE_INIT_16BIT_SUPPORT()\n"; 190 | 191 | foreach (sort { $a <=> $b } keys(%ordinalmap) ) { 192 | my $tableref = $ordinalmap{$_}; 193 | next if not $tableref->{'is16bit'}; 194 | my $fn = $tableref->{'fn'}; 195 | my $argstr = $tableref->{'args'}; 196 | my $argbytes = 0; 197 | my @args = (); 198 | 199 | if (($argstr ne 'VOID') and ($argstr ne 'void')) { 200 | @args = split /,/, $argstr; 201 | } 202 | 203 | foreach (@args) { 204 | my ($t, $n) = /\A\s*(.*?)\s+(.*?)\s*\Z/; 205 | $argbytes += typesize($t); 206 | } 207 | print OUT " LX_NATIVE_INIT_16BIT_BRIDGE($fn, $argbytes)\n"; 208 | } 209 | 210 | print OUT " LX_NATIVE_MODULE_INIT_16BIT_SUPPORT_END()\n"; 211 | print OUT " return 1;\n"; 212 | print OUT "}\n\n"; 213 | } 214 | 215 | print OUT "LX_NATIVE_MODULE_INIT("; 216 | if ($has16bitfns) { 217 | print OUT "{ if (!init16_$module()) return 0; }"; 218 | } 219 | print OUT ")\n"; 220 | 221 | my $comma = ''; 222 | foreach (sort { $a <=> $b } keys(%ordinalmap) ) { 223 | my $tableref = $ordinalmap{$_}; 224 | my $fn = $tableref->{'fn'}; 225 | my $expname = $tableref->{'expname'}; 226 | my $ordinal = $tableref->{'ordinal'}; 227 | my $suffix = $tableref->{'is16bit'} ? '16' : ''; 228 | 229 | print OUT $comma; 230 | if (defined $expname) { 231 | print OUT " LX_NATIVE_EXPORT${suffix}_DIFFERENT_NAME($fn, \"$expname\", $ordinal)"; 232 | } else { 233 | print OUT " LX_NATIVE_EXPORT${suffix}($fn, $ordinal)"; 234 | } 235 | $comma = ",\n"; 236 | } 237 | print OUT "\n"; 238 | 239 | print OUT <chChar = getchar(); 20 | return NO_ERROR; 21 | } // kbdCharIn 22 | 23 | APIRET16 KbdGetStatus(PKBDKEYINFO pkbci, HKBD hkbd) 24 | { 25 | TRACE_NATIVE("KbdGetStatus(%p, %u)", pkbci, hkbd); 26 | FIXME("stub"); 27 | memset(pkbci, '\0', sizeof (*pkbci)); 28 | return NO_ERROR; 29 | } 30 | 31 | APIRET16 KbdSetStatus(PKBDKEYINFO pkbci, HKBD hkbd) 32 | { 33 | TRACE_NATIVE("KbdSetStatus(%p, %u)", pkbci, hkbd); 34 | FIXME("stub"); 35 | return NO_ERROR; 36 | } 37 | 38 | APIRET16 KbdStringIn(PCHAR pch, PSTRINGINBUF pchin, USHORT flag, HKBD hkbd) 39 | { 40 | TRACE_NATIVE("KbdStringIn(%p, %p, %u, %u)", pch, pchin, flag, hkbd); 41 | if (!pch) return ERROR_INVALID_PARAMETER; 42 | int count = 0; 43 | char chr = getchar(); 44 | while ((chr != '\r') && (chr != '\n') && (count < pchin->cb)) 45 | { 46 | pch[count++] = chr; 47 | chr = getchar(); 48 | } 49 | if (count < (pchin->cb - 1)) 50 | { 51 | pch[count] = '\r'; 52 | } 53 | if (pchin) pchin->cchIn = count; 54 | return NO_ERROR; 55 | } 56 | 57 | // end of kbdcalls.c ... 58 | 59 | -------------------------------------------------------------------------------- /native/kbdcalls.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_KBDCALLS_H_ 10 | #define _INCL_KBDCALLS_H_ 11 | 12 | #include "os2types.h" 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #pragma pack(push, 2) 19 | typedef struct 20 | { 21 | UCHAR chChar; 22 | UCHAR chScan; 23 | UCHAR fbStatus; 24 | UCHAR bNlsShift; 25 | USHORT fsState; 26 | ULONG time; 27 | } KBDKEYINFO, *PKBDKEYINFO; 28 | 29 | typedef struct 30 | { 31 | USHORT cb; 32 | USHORT cchIn; 33 | } STRINGINBUF, *PSTRINGINBUF; 34 | #pragma pack(pop) 35 | 36 | OS2EXPORT APIRET16 OS2API16 KbdCharIn(PKBDKEYINFO pkbci, USHORT fWait, HKBD hkbd) OS2APIINFO(ord=4,name=KBDCHARIN); 37 | OS2EXPORT APIRET16 OS2API16 KbdStringIn(PCHAR pch, PSTRINGINBUF pchin, USHORT flag, HKBD hkbd) OS2APIINFO(ord=9,name=KBDSTRINGIN); 38 | OS2EXPORT APIRET16 OS2API16 KbdGetStatus(PKBDKEYINFO pkbci, HKBD hkbd) OS2APIINFO(ord=10,name=KBDGETSTATUS); 39 | OS2EXPORT APIRET16 OS2API16 KbdSetStatus(PKBDKEYINFO pkbci, HKBD hkbd) OS2APIINFO(ord=11,name=KBDSETSTATUS); 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | #endif 46 | 47 | // end of kbdcalls.h ... 48 | 49 | -------------------------------------------------------------------------------- /native/mdm.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #include "os2native.h" 10 | #include "mdm.h" 11 | 12 | LX_NATIVE_MODULE_INIT() 13 | LX_NATIVE_MODULE_INIT_END() 14 | 15 | // end of mdm.c ... 16 | 17 | -------------------------------------------------------------------------------- /native/mdm.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_MDM_H_ 10 | #define _INCL_MDM_H_ 11 | 12 | #include "os2types.h" 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | #endif 23 | 24 | // end of mdm.h ... 25 | 26 | -------------------------------------------------------------------------------- /native/msg-lx.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | */ 6 | 7 | /* THIS FILE IS AUTOGENERATED. DO NOT EDIT BY HAND. see lxapigen.pl */ 8 | 9 | /* This is glue code for OS/2 binaries. Native binaries don't need this. */ 10 | #if LX_LEGACY 11 | 12 | static APIRET16 bridge16to32_Dos16PutMessage(uint8 *args) { 13 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PCHAR, pBuf); 14 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, cbMsg); 15 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, hfile); 16 | return Dos16PutMessage(hfile, cbMsg, pBuf); 17 | } 18 | 19 | static APIRET16 bridge16to32_Dos16TrueGetMessage(uint8 *args) { 20 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PVOID, msgseg); 21 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PUSHORT, pcbMsg); 22 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PCHAR, pFilename); 23 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, msgnum); 24 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, cbBuf); 25 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PCHAR, pData); 26 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, cTable); 27 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PVOID, pTable); 28 | return Dos16TrueGetMessage(pTable, cTable, pData, cbBuf, msgnum, pFilename, pcbMsg, msgseg); 29 | } 30 | 31 | LX_NATIVE_MODULE_16BIT_SUPPORT() 32 | LX_NATIVE_MODULE_16BIT_API(Dos16PutMessage) 33 | LX_NATIVE_MODULE_16BIT_API(Dos16TrueGetMessage) 34 | LX_NATIVE_MODULE_16BIT_SUPPORT_END() 35 | 36 | LX_NATIVE_MODULE_DEINIT({ 37 | LX_NATIVE_MODULE_DEINIT_16BIT_SUPPORT(); 38 | }) 39 | 40 | static int init16_msg(void) { 41 | LX_NATIVE_MODULE_INIT_16BIT_SUPPORT() 42 | LX_NATIVE_INIT_16BIT_BRIDGE(Dos16PutMessage, 8) 43 | LX_NATIVE_INIT_16BIT_BRIDGE(Dos16TrueGetMessage, 26) 44 | LX_NATIVE_MODULE_INIT_16BIT_SUPPORT_END() 45 | return 1; 46 | } 47 | 48 | LX_NATIVE_MODULE_INIT({ if (!init16_msg()) return 0; }) 49 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(Dos16PutMessage, "DOSPUTMESSAGE", 1), 50 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(Dos16TrueGetMessage, "DOSTRUEGETMESSAGE", 2), 51 | LX_NATIVE_EXPORT(DosPutMessage, 5), 52 | LX_NATIVE_EXPORT(DosTrueGetMessage, 6) 53 | LX_NATIVE_MODULE_INIT_END() 54 | 55 | #endif /* LX_LEGACY */ 56 | 57 | /* end of msg-lx.h ... */ 58 | 59 | -------------------------------------------------------------------------------- /native/msg.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #include "os2native16.h" 10 | #include "msg.h" 11 | 12 | #include 13 | 14 | #include "msg-lx.h" 15 | 16 | APIRET DosPutMessage(HFILE handle, ULONG msglen, PCHAR msg) 17 | { 18 | TRACE_NATIVE("DosPutMessage(%u, %u, %p)", (uint) handle, (uint) msglen, msg); 19 | FIXME("really implement this"); 20 | write(handle, msg, msglen); 21 | return NO_ERROR; 22 | } // DosPutMessage 23 | 24 | APIRET16 Dos16PutMessage(USHORT handle, USHORT msglen, PCHAR msg) 25 | { 26 | TRACE_NATIVE("Dos16PutMessage(%u, %u, %p)", (uint) handle, (uint) msglen, msg); 27 | FIXME("really implement this"); 28 | write(handle, msg, msglen); 29 | return NO_ERROR; 30 | } // Dos16PutMessage 31 | 32 | APIRET16 Dos16TrueGetMessage(PVOID pTable, USHORT cTable, PCHAR pData, USHORT cbBuf, USHORT msgnum, PCHAR pFilename, PUSHORT pcbMsg, PVOID msgseg) 33 | { 34 | TRACE_NATIVE("Dos16TrueGetMessage(%p, %u, %p, %u, %u, %p, %p, %p)", pTable, cTable, pData, cbBuf, msgnum, pFilename, pcbMsg, msgseg); 35 | void *msgdat = msgseg; 36 | int offset = *(uint16_t *)(msgdat + 14); 37 | offset = *(uint16_t *)(msgdat + offset + 4); 38 | int count = *(uint16_t *)(msgdat + offset + 3); 39 | uint16_t *msgarr = (uint16_t *)(msgdat + offset + 5); 40 | int i, j = 0; 41 | for (i = 0; i < count; i++) 42 | { 43 | if(*(uint16_t *)(msgdat + msgarr[i]) == msgnum) 44 | break; 45 | } 46 | if (i == count) return ERROR_MR_MID_NOT_FOUND; 47 | int msglen = *(PUSHORT)(msgdat + msgarr[i] + 2); 48 | char *substr, *msg = (char *)(msgdat + msgarr[i] + 4); 49 | int sub; 50 | if (msg[0] == 'E') 51 | { 52 | j = 8; 53 | if (cbBuf > 8) 54 | sprintf(pData, "SYS%04d:", msgnum); 55 | } 56 | for (i = 1; (i < msglen) && (j < cbBuf); i++, j++) 57 | { 58 | if (msg[i] == '%') 59 | { 60 | sub = msg[++i] - '1'; 61 | if ((sub < 0) || (sub >= cTable)) return ERROR_MR_INV_MSGF_FORMAT; 62 | substr = GLoaderState.convert1616to32(((uint32_t *)pTable)[sub]); 63 | strcpy(&pData[j], substr); 64 | j += strlen(substr) - 1; 65 | } 66 | else 67 | pData[j] = msg[i]; 68 | } 69 | *pcbMsg = j; 70 | return NO_ERROR; 71 | } 72 | 73 | APIRET DosTrueGetMessage(PVOID msgseg, PVOID pTable, ULONG cTable, PCHAR pData, ULONG cbBuf, ULONG msgnum, PCHAR pFilename, PULONG pcbMsg) 74 | { 75 | TRACE_NATIVE("DosTrueGetMessage(%p, %p, %u, %p, %u, %u, '%s', %p)", msgseg, pTable, cTable, pData, cbBuf, msgnum, pFilename, pcbMsg); 76 | FIXME("really implement this"); 77 | const char *msgstr = "SYSXXX: DosTrueGetMessage is not yet implemented."; 78 | ULONG rc = 0; 79 | if (pData) { 80 | rc = (ULONG) snprintf(pData, cbBuf, "%s", msgstr); 81 | if (rc >= cbBuf) { 82 | rc = cbBuf; 83 | } 84 | } 85 | if (pcbMsg) *pcbMsg = rc; 86 | return ERROR_MR_MID_NOT_FOUND; 87 | } 88 | 89 | // end of msg.c ... 90 | 91 | -------------------------------------------------------------------------------- /native/msg.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_MSG_H_ 10 | #define _INCL_MSG_H_ 11 | 12 | #include "os2types.h" 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | OS2EXPORT APIRET16 OS2API16 Dos16PutMessage(USHORT hfile, USHORT cbMsg, PCHAR pBuf) OS2APIINFO(ord=1,name=DOSPUTMESSAGE); 19 | OS2EXPORT APIRET16 OS2API16 Dos16TrueGetMessage(PVOID pTable, USHORT cTable, PCHAR pData, USHORT cbBuf, USHORT msgnum, PCHAR pFilename, PUSHORT pcbMsg, PVOID msgseg) OS2APIINFO(ord=2,name=DOSTRUEGETMESSAGE); 20 | OS2EXPORT APIRET OS2API DosPutMessage(HFILE hfile, ULONG cbMsg, PCHAR pBuf) OS2APIINFO(5); 21 | OS2EXPORT APIRET OS2API DosTrueGetMessage(PVOID msgseg, PVOID pTable, ULONG cTable, PCHAR pData, ULONG cbBuf, ULONG msgnum, PCHAR pFilename, PULONG pcbMsg) OS2APIINFO(6); 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | 27 | #endif 28 | 29 | // end of msg.h ... 30 | 31 | -------------------------------------------------------------------------------- /native/nls-lx.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | */ 6 | 7 | /* THIS FILE IS AUTOGENERATED. DO NOT EDIT BY HAND. see lxapigen.pl */ 8 | 9 | /* This is glue code for OS/2 binaries. Native binaries don't need this. */ 10 | #if LX_LEGACY 11 | 12 | static APIRET16 bridge16to32_Dos16GetDBCSEv(uint8 *args) { 13 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PCHAR, buf); 14 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PCOUNTRYCODE16, pcc); 15 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, buflen); 16 | return Dos16GetDBCSEv(buflen, pcc, buf); 17 | } 18 | 19 | static APIRET16 bridge16to32_Dos16CaseMap(uint8 *args) { 20 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PCHAR, pch); 21 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PCOUNTRYCODE16, pcc); 22 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, len); 23 | return Dos16CaseMap(len, pcc, pch); 24 | } 25 | 26 | static APIRET16 bridge16to32_Dos16GetCtryInfo(uint8 *args) { 27 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PUSHORT, dlen); 28 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PCOUNTRYINFO16, pch); 29 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PCOUNTRYCODE16, pcc); 30 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, len); 31 | return Dos16GetCtryInfo(len, pcc, pch, dlen); 32 | } 33 | 34 | LX_NATIVE_MODULE_16BIT_SUPPORT() 35 | LX_NATIVE_MODULE_16BIT_API(Dos16GetDBCSEv) 36 | LX_NATIVE_MODULE_16BIT_API(Dos16CaseMap) 37 | LX_NATIVE_MODULE_16BIT_API(Dos16GetCtryInfo) 38 | LX_NATIVE_MODULE_16BIT_SUPPORT_END() 39 | 40 | LX_NATIVE_MODULE_DEINIT({ 41 | LX_NATIVE_MODULE_DEINIT_16BIT_SUPPORT(); 42 | }) 43 | 44 | static int init16_nls(void) { 45 | LX_NATIVE_MODULE_INIT_16BIT_SUPPORT() 46 | LX_NATIVE_INIT_16BIT_BRIDGE(Dos16GetDBCSEv, 10) 47 | LX_NATIVE_INIT_16BIT_BRIDGE(Dos16CaseMap, 10) 48 | LX_NATIVE_INIT_16BIT_BRIDGE(Dos16GetCtryInfo, 14) 49 | LX_NATIVE_MODULE_INIT_16BIT_SUPPORT_END() 50 | return 1; 51 | } 52 | 53 | LX_NATIVE_MODULE_INIT({ if (!init16_nls()) return 0; }) 54 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(Dos16GetDBCSEv, "DOSGETDBCSEV", 4), 55 | LX_NATIVE_EXPORT(DosQueryCtryInfo, 5), 56 | LX_NATIVE_EXPORT(DosQueryDBCSEnv, 6), 57 | LX_NATIVE_EXPORT(DosMapCase, 7), 58 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(Dos16CaseMap, "DOSCASEMAP", 391), 59 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(Dos16GetCtryInfo, "DOSGETCTRYINFO", 393) 60 | LX_NATIVE_MODULE_INIT_END() 61 | 62 | #endif /* LX_LEGACY */ 63 | 64 | /* end of nls-lx.h ... */ 65 | 66 | -------------------------------------------------------------------------------- /native/nls.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #include "os2native16.h" 10 | #include "nls.h" 11 | 12 | #include "nls-lx.h" 13 | 14 | APIRET16 Dos16GetDBCSEv(USHORT buflen, PCOUNTRYCODE16 pcc, PCHAR buf) 15 | { 16 | // !!! FIXME: implement this for real. 17 | TRACE_NATIVE("Dos16GetDBCSEv(%u, %p, %p)", (uint) buflen, pcc, buf); 18 | if ((pcc->country != 0) || (pcc->codepage != 0)) 19 | return ERROR_CODE_PAGE_NOT_FOUND; 20 | memset(buf, '\0', buflen); 21 | return NO_ERROR; 22 | } // Dos16GetDBCSEv 23 | 24 | APIRET16 Dos16CaseMap(USHORT len, PCOUNTRYCODE16 pcc, PCHAR pch) 25 | { 26 | TRACE_NATIVE("Dos16CaseMap(%u, %p, %p)", (uint) len, pcc, pch); 27 | if (!pcc) return ERROR_INVALID_PARAMETER; 28 | COUNTRYCODE cc = {pcc->country, pcc->codepage}; 29 | APIRET16 ret = DosMapCase(len, &cc, pch); 30 | pcc->country = cc.country; 31 | pcc->codepage = cc.codepage; 32 | return ret; 33 | } 34 | 35 | APIRET16 Dos16GetCtryInfo(USHORT len, PCOUNTRYCODE16 pcc, PCOUNTRYINFO16 pch, PUSHORT dlen) 36 | { 37 | TRACE_NATIVE("Dos16GetCtryInfo(%u, %p, %p)",len, pcc, pch); 38 | if (!pcc || !pch || (len < 6)) return ERROR_INVALID_PARAMETER; 39 | COUNTRYINFO ci; 40 | COUNTRYCODE cc = {pcc->country, pcc->codepage}; 41 | APIRET16 ret = DosQueryCtryInfo(sizeof(ci), &cc, &ci, NULL); 42 | if (ret) return ret; 43 | pch->country = ci.country; 44 | pch->codepage = ci.codepage; 45 | pch->fsDateFmt = ci.fsDateFmt; 46 | memcpy(&pch->szCurrency, &ci.szCurrency, len - 6); 47 | if (dlen) *dlen = sizeof(PCOUNTRYCODE16); 48 | return NO_ERROR; 49 | } 50 | 51 | APIRET DosQueryDBCSEnv(ULONG buflen, PCOUNTRYCODE pcc, PCHAR buf) 52 | { 53 | // !!! FIXME: implement this for real. 54 | TRACE_NATIVE("DosQueryDBCSEnv(%u, %p, %p)", (uint) buflen, pcc, buf); 55 | if ((pcc->country != 0) || (pcc->codepage != 0)) 56 | return ERROR_CODE_PAGE_NOT_FOUND; 57 | memset(buf, '\0', buflen); 58 | return NO_ERROR; 59 | } // DosQueryDBCSEnv 60 | 61 | APIRET DosMapCase(ULONG cb, PCOUNTRYCODE pcc, PCHAR pch) 62 | { 63 | // !!! FIXME: implement this for real. 64 | TRACE_NATIVE("DosMapCase(%u, %p, %p)", (uint) cb, pcc, pch); 65 | if ((pcc->country != 0) || (pcc->codepage != 0)) 66 | return ERROR_CODE_PAGE_NOT_FOUND; 67 | 68 | for (ULONG i = 0; i < cb; i++) { 69 | const CHAR ch = *pch; 70 | *(pch++) = ((ch >= 'A') && (ch <= 'Z')) ? ch - ('A' - 'a') : ch; 71 | } // for 72 | 73 | return NO_ERROR; 74 | } // DosMapCase 75 | 76 | APIRET DosQueryCtryInfo(ULONG cb, PCOUNTRYCODE pcc, PCOUNTRYINFO pci, PULONG pcbActual) 77 | { 78 | // From the 4.5 toolkit docs: "If this area is too small to hold all of 79 | // the available information, then as much information as possible is 80 | // provided in the available space (in the order in which the data would 81 | // appear)." ...so we fill in a local struct and memcpy it at the end. 82 | COUNTRYINFO ci; 83 | memset(&ci, '\0', sizeof (ci)); 84 | 85 | // From the 4.5 toolkit docs: "If the amount of data returned is not 86 | // enough to fill the memory area provided by the caller, then the memory 87 | // that is unaltered by the available data is zeroed out." ...so blank 88 | // it all out now. 89 | memset(pci, '\0', cb); 90 | 91 | if ((pcc->country != 0) || (pcc->codepage != 0)) 92 | return ERROR_CODE_PAGE_NOT_FOUND; 93 | 94 | // !!! FIXME: this is just what OS/2 Warp 4.52 returns by default for my USA system. 95 | ci.country = 1; 96 | ci.codepage = 437; 97 | ci.fsDateFmt = 0; 98 | ci.szCurrency[0] = '$'; 99 | ci.szThousandsSeparator[0] = ','; 100 | ci.szDecimal[0] = '.'; 101 | ci.szDateSeparator[0] = '-'; 102 | ci.szTimeSeparator[0] = ':'; 103 | ci.fsCurrencyFmt = 0;; 104 | ci.cDecimalPlace = 2; 105 | ci.fsTimeFmt = 0; 106 | //USHORT abReserved1[2]; 107 | ci.szDataSeparator[0] = ','; 108 | //USHORT abReserved2[5]; 109 | 110 | if (pcbActual) 111 | *pcbActual = 38; // OS/2 Warp 4.52 doesn't count the abReserved[5] at the end. 112 | 113 | memcpy(pci, &ci, cb); 114 | 115 | return NO_ERROR; 116 | } // DosQueryCtryInfo 117 | 118 | // end of nls.c ... 119 | 120 | -------------------------------------------------------------------------------- /native/nls.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_NLS_H_ 10 | #define _INCL_NLS_H_ 11 | 12 | #include "os2types.h" 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | typedef struct 19 | { 20 | ULONG country; 21 | ULONG codepage; 22 | } COUNTRYCODE, *PCOUNTRYCODE; 23 | 24 | typedef struct 25 | { 26 | ULONG country; 27 | ULONG codepage; 28 | ULONG fsDateFmt; 29 | CHAR szCurrency[5]; 30 | CHAR szThousandsSeparator[2]; 31 | CHAR szDecimal[2]; 32 | CHAR szDateSeparator[2]; 33 | CHAR szTimeSeparator[2]; 34 | UCHAR fsCurrencyFmt; 35 | UCHAR cDecimalPlace; 36 | UCHAR fsTimeFmt; 37 | USHORT abReserved1[2]; 38 | CHAR szDataSeparator[2]; 39 | USHORT abReserved2[5]; 40 | } COUNTRYINFO, *PCOUNTRYINFO; 41 | 42 | OS2EXPORT APIRET OS2API DosQueryDBCSEnv(ULONG cb, PCOUNTRYCODE pcc, PCHAR pBuf) OS2APIINFO(6); 43 | OS2EXPORT APIRET OS2API DosMapCase(ULONG cb, PCOUNTRYCODE pcc, PCHAR pch) OS2APIINFO(7); 44 | OS2EXPORT APIRET OS2API DosQueryCtryInfo(ULONG cb, PCOUNTRYCODE pcc, PCOUNTRYINFO pci, PULONG pcbActual) OS2APIINFO(5); 45 | 46 | 47 | typedef struct 48 | { 49 | USHORT country; 50 | USHORT codepage; 51 | } COUNTRYCODE16, *PCOUNTRYCODE16; 52 | 53 | typedef struct 54 | { 55 | USHORT country; 56 | USHORT codepage; 57 | USHORT fsDateFmt; 58 | CHAR szCurrency[5]; 59 | CHAR szThousandsSeparator[2]; 60 | CHAR szDecimal[2]; 61 | CHAR szDateSeparator[2]; 62 | CHAR szTimeSeparator[2]; 63 | UCHAR fsCurrencyFmt; 64 | UCHAR cDecimalPlace; 65 | UCHAR fsTimeFmt; 66 | USHORT abReserved1[2]; 67 | CHAR szDataSeparator[2]; 68 | USHORT abReserved2[5]; 69 | } COUNTRYINFO16, *PCOUNTRYINFO16; 70 | 71 | OS2EXPORT APIRET16 OS2API16 Dos16GetDBCSEv(USHORT buflen, PCOUNTRYCODE16 pcc, PCHAR buf) OS2APIINFO(ord=4,name=DOSGETDBCSEV); 72 | OS2EXPORT APIRET16 OS2API16 Dos16CaseMap(USHORT len, PCOUNTRYCODE16 pcc, PCHAR pch) OS2APIINFO(ord=391,name=DOSCASEMAP); 73 | OS2EXPORT APIRET16 OS2API16 Dos16GetCtryInfo(USHORT len, PCOUNTRYCODE16 pcc, PCOUNTRYINFO16 pch, PUSHORT dlen) OS2APIINFO(ord=393,name=DOSGETCTRYINFO); 74 | 75 | #ifdef __cplusplus 76 | } 77 | #endif 78 | 79 | #endif 80 | 81 | // end of nls.h ... 82 | 83 | -------------------------------------------------------------------------------- /native/os2.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_OS2_H_ 10 | #define _INCL_OS2_H_ 11 | 12 | // !!! FIXME: the official toolkit headers have all sorts of tapdancing with 13 | // "#ifdef INCL_DOSPROCESS" and "#define INCL_DOSINCLUDED" and stuff. 14 | // !!! FIXME: naturally, these filenames don't match either, but this isn't 15 | // !!! FIXME: meant to be a drop-in replacement. At least: not at the moment. 16 | 17 | #include "os2types.h" 18 | #include "os2errors.h" 19 | #include "doscalls.h" 20 | #include "kbdcalls.h" 21 | #include "viocalls.h" 22 | #include "quecalls.h" 23 | #include "msg.h" 24 | #include "nls.h" 25 | #include "sesmgr.h" 26 | #include "pmgpi.h" 27 | #include "tcpip32.h" 28 | 29 | #endif 30 | 31 | // end of os2.h ... 32 | -------------------------------------------------------------------------------- /native/os2native.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_OS2NATIVE_H_ 10 | #define _INCL_OS2NATIVE_H_ 11 | 12 | /* Unless forced off, build in support for OS/2 binaries (the LX export tables, 16-bit bridge code, etc) */ 13 | #ifndef LX_LEGACY 14 | #define LX_LEGACY 1 15 | #endif 16 | 17 | #define _DARWIN_C_SOURCE 1 18 | #define _POSIX_C_SOURCE 199309 19 | #define _DEFAULT_SOURCE 20 | #define _GNU_SOURCE 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "os2types.h" 30 | #include "os2errors.h" 31 | #include "../lib2ine.h" 32 | 33 | #if 1 34 | #define TRACE_NATIVE(...) do { if (GLoaderState.trace_native) { fprintf(stderr, "2INE TRACE [%lu]: ", (unsigned long) pthread_self()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, ";\n"); } } while (0) 35 | #else 36 | #define TRACE_NATIVE(...) do {} while (0) 37 | #endif 38 | 39 | #if 1 40 | #define TRACE_EVENT(...) do { if (GLoaderState.trace_events) { fprintf(stderr, "2INE TRACE [%lu]: ", (unsigned long) pthread_self()); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } } while (0) 41 | #else 42 | #define TRACE_EVENT(...) do {} while (0) 43 | #endif 44 | 45 | OS2EXPORT const LxExport * lxNativeModuleInit(uint32 *lx_num_exports); 46 | OS2EXPORT void lxNativeModuleDeinit(void); 47 | 48 | #define LX_NATIVE_MODULE_DEINIT(deinitcode) \ 49 | void lxNativeModuleDeinit(void) { \ 50 | deinitcode; \ 51 | } 52 | 53 | #define LX_NATIVE_MODULE_INIT(initcode) \ 54 | const LxExport *lxNativeModuleInit(uint32 *lx_num_exports) { \ 55 | initcode; \ 56 | static const LxExport lx_native_exports[] = { 57 | 58 | #define LX_NATIVE_EXPORT(fn, ord) { ord, #fn, fn, NULL } 59 | #define LX_NATIVE_EXPORT_DIFFERENT_NAME(fn, fnname, ord) { ord, fnname, fn, NULL } 60 | 61 | #define LX_NATIVE_MODULE_INIT_END() \ 62 | }; \ 63 | *lx_num_exports = sizeof (lx_native_exports) / sizeof (lx_native_exports[0]); \ 64 | return lx_native_exports; \ 65 | } 66 | 67 | // we store the TIB2 struct right after the TIB struct on the stack, 68 | // so get the TIB, then step forward to the TIB2. 69 | #define LX_GETTIB() ((LxTIB *) GLoaderState.getOs2Tib()) 70 | #define LX_GETTIB2() ((LxTIB2 *) (LX_GETTIB() + 1)) 71 | #define LX_GETPOSTTIB() ((LxPostTIB *) (LX_GETTIB2() + 1)) 72 | 73 | #endif 74 | 75 | // end of os2native.h ... 76 | 77 | -------------------------------------------------------------------------------- /native/os2native16.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_OS2NATIVE16_H_ 10 | #define _INCL_OS2NATIVE16_H_ 11 | 12 | #include "os2native.h" 13 | 14 | // !!! FIXME: _lots_ of macro salsa in here. 15 | 16 | #define LX_NATIVE_MODULE_16BIT_SUPPORT() \ 17 | static LxMmaps obj16; 18 | 19 | // These are the 16-bit entry points, which are exported to the LX loader 20 | // (not when linking directly to this shared library). 21 | #define LX_NATIVE_MODULE_16BIT_API(fn) \ 22 | static void *fn##16 = NULL; 23 | 24 | #define LX_NATIVE_MODULE_16BIT_SUPPORT_END() 25 | 26 | #define LX_NATIVE_MODULE_DEINIT_16BIT_SUPPORT() \ 27 | if (obj16.alias != 0xFFFF) { \ 28 | GLoaderState.freeSelector(obj16.alias); \ 29 | } \ 30 | if (obj16.mapped != NULL) { \ 31 | munmap(obj16.mapped, obj16.size); \ 32 | } \ 33 | obj16.mapped = obj16.addr = NULL; \ 34 | obj16.size = 0; \ 35 | obj16.alias = 0xFFFF; \ 36 | 37 | #define LX_NATIVE_MODULE_INIT_16BIT_SUPPORT() \ 38 | obj16.mapped = obj16.addr = NULL; \ 39 | obj16.size = 0; \ 40 | obj16.alias = 0xFFFF; \ 41 | \ 42 | const size_t vsize = 0x10000 * 2; \ 43 | void *mmapaddr = mmap(NULL, vsize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); \ 44 | if (mmapaddr == ((void *) MAP_FAILED)) { \ 45 | fprintf(stderr, "mmap(NULL, 0x20000, RW-, ANON|PRIVATE, -1, 0) failed (%d): %s\n", errno, strerror(errno)); \ 46 | return 0; \ 47 | } \ 48 | \ 49 | obj16.mapped = mmapaddr; \ 50 | obj16.size = vsize; \ 51 | \ 52 | /* force objects with a 16:16 alias to a 64k boundary. */ \ 53 | size_t adjust = (size_t) mmapaddr; \ 54 | if ((adjust % 0x10000) != 0) { \ 55 | const size_t diff = 0x10000 - (adjust % 0x10000); \ 56 | adjust += diff; \ 57 | mmapaddr = (void *) adjust; \ 58 | } \ 59 | obj16.addr = mmapaddr; \ 60 | \ 61 | uint16 offset = 0; \ 62 | if (!GLoaderState.findSelector((uint32) obj16.addr, &obj16.alias, &offset, 1)) { \ 63 | fprintf(stderr, "couldn't find a selector for 16-bit entry points!\n"); \ 64 | munmap(obj16.mapped, vsize); \ 65 | obj16.mapped = obj16.addr = NULL; \ 66 | obj16.size = 0; \ 67 | obj16.alias = 0xFFFF; \ 68 | return 0; \ 69 | } \ 70 | assert(offset == 0); \ 71 | \ 72 | uint8 *ptr = (uint8 *) mmapaddr; 73 | 74 | 75 | /* This is the original assembly code, for use with NASM. 76 | USE16 ; start in 16-bit code where our 16-bit caller lands. 77 | PUSH BX ; this might be overkill, but save off everything you can, just in case. 78 | PUSH CX 79 | PUSH DX 80 | PUSH SI 81 | PUSH DI 82 | PUSH BP 83 | MOV CX, SP ; save off sp 84 | JMP DWORD 0x7788:0x33332222 ; jmp into the 32-bit code segment (the next instruction!). 85 | 86 | USE32 87 | MOV BX, SS ; save off ss 88 | SHL EBX, 16 ; scootch over! 89 | MOV BX, CX ; %ebx now has 16-bit ss:sp 90 | 91 | ; our stack is tiled, so we can easily find the linear address of it. 92 | MOV AX, SS ; move the stack segment into the low word. 93 | SHR AX, 3 ; shift out the control bits from the segment. 94 | SHL EAX, 16 ; move the remaining selector bits to the high word of %eax 95 | MOV AX, CX ; move the stack offset into the low word. Now %eax has the linear stack pointer. 96 | 97 | MOV CX, 0xABCD ; original linear stack segment from lx_loader's main(). 98 | MOV SS, CX 99 | MOV ESP, EAX ; and the same stack pointer, but linear. 100 | ADD EAX, 16 ; %eax now points to original function arguments on the stack. 101 | 102 | PUSH EBX ; save original ss:sp to stack. 103 | PUSH DS ; save off the caller's data segment. 104 | PUSH ES ; save off the caller's %es register. 105 | 106 | MOV CX, 0x8888 ; restore our linear data segment. 107 | MOV DS, CX 108 | 109 | MOV CX, 0x9999 ; restore %es register. 110 | MOV ES, CX 111 | 112 | PUSH EAX ; make this the sole argument to the bridge function. 113 | MOV EAX, 0x55555555 ; absolute address of our 32-bit bridging function in C. 114 | CALL [EAX] ; call our 32-bit bridging function in C. 115 | ; don't touch EAX anymore, it has the return value now! 116 | ADD ESP, 4 ; dump our function argument. 117 | 118 | POP ES ; get back caller's %es register. 119 | POP DS ; get back our 16-bit data segment. 120 | 121 | ; Restore 16:16 stack. !!! FIXME: can use LSS if we figure out prefix and DS politics. 122 | POP BX ; Get our original sp back. 123 | POP CX ; Get our original ss back. 124 | 125 | JMP WORD 0xAAAA:0xBBBB ; back into 16-bit land (the next instruction!). 126 | 127 | USE16 128 | MOV SS, CX 129 | MOV SP, BX 130 | 131 | POP BP ; restore all our overkill registers 132 | POP DI 133 | POP SI 134 | POP DX 135 | POP CX 136 | POP BX 137 | 138 | RETF 0x22 ; ...and back to the (far) caller, clearing the args (Pascal calling convention!) with retval in AX. 139 | */ 140 | 141 | #define LX_NATIVE_INIT_16BIT_BRIDGE(fn, argbytes) { \ 142 | fn##16 = ptr; \ 143 | \ 144 | /* instructions are in Intel syntax here, not AT&T. */ \ 145 | /* USE16 */ \ 146 | *(ptr++) = 0x53; /* push bx */ \ 147 | *(ptr++) = 0x51; /* push cx */ \ 148 | *(ptr++) = 0x52; /* push dx */ \ 149 | *(ptr++) = 0x56; /* push si */ \ 150 | *(ptr++) = 0x57; /* push di */ \ 151 | *(ptr++) = 0x55; /* push bp */ \ 152 | *(ptr++) = 0x89; /* mov cx,sp... */ \ 153 | *(ptr++) = 0xE1; /* ...mov cx,sp */ \ 154 | *(ptr++) = 0x66; /* jmp dword 0x7788:0x33332222... */ \ 155 | *(ptr++) = 0xEA; /* ...jmp dword 0x7788:0x33332222 */ \ 156 | const uint32 jmp32addr = (uint32) (ptr + 6); \ 157 | memcpy(ptr, &jmp32addr, 4); ptr += 4; \ 158 | memcpy(ptr, &GLoaderState.original_cs, 2); ptr += 2; \ 159 | \ 160 | /* USE32 */ \ 161 | *(ptr++) = 0x66; /* mov bx,ss... */ \ 162 | *(ptr++) = 0x8C; /* ...mov bx,ss */ \ 163 | *(ptr++) = 0xD3; /* ...mov bx,ss */ \ 164 | *(ptr++) = 0xC1; /* shl ebx,byte 0x10... */ \ 165 | *(ptr++) = 0xE3; /* ...shl ebx,byte 0x10 */ \ 166 | *(ptr++) = 0x10; /* ...shl ebx,byte 0x10 */ \ 167 | *(ptr++) = 0x66; /* mov bx,cx... */ \ 168 | *(ptr++) = 0x89; /* ...mov bx,cx */ \ 169 | *(ptr++) = 0xCB; /* ...mov bx,cx */ \ 170 | *(ptr++) = 0x66; /* mov ax,ss... */ \ 171 | *(ptr++) = 0x8C; /* ...mov ax,ss */ \ 172 | *(ptr++) = 0xD0; /* ...mov ax,ss */ \ 173 | *(ptr++) = 0x66; /* shr ax,byte 0x3... */ \ 174 | *(ptr++) = 0xC1; /* ...shr ax,byte 0x3 */ \ 175 | *(ptr++) = 0xE8; /* ...shr ax,byte 0x3 */ \ 176 | *(ptr++) = 0x03; /* ...shr ax,byte 0x3 */ \ 177 | *(ptr++) = 0xC1; /* shl eax,byte 0x10... */ \ 178 | *(ptr++) = 0xE0; /* ...shl eax,byte 0x10 */ \ 179 | *(ptr++) = 0x10; /* ...shl eax,byte 0x10 */ \ 180 | *(ptr++) = 0x66; /* mov ax,cx... */ \ 181 | *(ptr++) = 0x89; /* ...mov ax,cx */ \ 182 | *(ptr++) = 0xC8; /* ...mov ax,cx */ \ 183 | *(ptr++) = 0x66; /* mov cx,0xabcd... */ \ 184 | *(ptr++) = 0xB9; /* ...mov cx,0xabcd */ \ 185 | memcpy(ptr, &GLoaderState.original_ss, 2); ptr += 2; \ 186 | *(ptr++) = 0x8E; /* mov ss,ecx... */ \ 187 | *(ptr++) = 0xD1; /* ...mov ss,ecx */ \ 188 | *(ptr++) = 0x89; /* mov esp,eax... */ \ 189 | *(ptr++) = 0xC4; /* ...mov esp,eax */ \ 190 | *(ptr++) = 0x83; /* add eax,byte +0x10... */ \ 191 | *(ptr++) = 0xC0; /* ...add eax,byte +0x10 */ \ 192 | *(ptr++) = 0x10; /* ...add eax,byte +0x10 */ \ 193 | *(ptr++) = 0x53; /* push ebx */ \ 194 | *(ptr++) = 0x1E; /* push ds */ \ 195 | *(ptr++) = 0x06; /* push es */ \ 196 | if (GLoaderState.original_ss != GLoaderState.original_ds) { \ 197 | *(ptr++) = 0x66; /* mov cx,0x8888... */ \ 198 | *(ptr++) = 0xB9; /* ...mov cx,0x8888 */ \ 199 | memcpy(ptr, &GLoaderState.original_ds, 2); ptr += 2; \ 200 | } \ 201 | *(ptr++) = 0x8E; /* mov ds,ecx... */ \ 202 | *(ptr++) = 0xD9; /* ...mov ds,ecx */ \ 203 | if (GLoaderState.original_ds != GLoaderState.original_es) { \ 204 | *(ptr++) = 0x66; /* mov cx,0x9999... */ \ 205 | *(ptr++) = 0xB9; /* ...mov cx,0x9999 */ \ 206 | memcpy(ptr, &GLoaderState.original_es, 2); ptr += 2; \ 207 | } \ 208 | *(ptr++) = 0x8E; /* mov es,ecx... */ \ 209 | *(ptr++) = 0xC1; /* ...mov es,ecx */ \ 210 | *(ptr++) = 0x50; /* push eax */ \ 211 | *(ptr++) = 0xB8; /* mov eax,0x55555555... */ \ 212 | const uint32 callbridgeaddr = (uint32) bridge16to32_##fn; \ 213 | memcpy(ptr, &callbridgeaddr, 4); ptr += 4; \ 214 | *(ptr++) = 0xFF; /* call dword [eax]... */ \ 215 | *(ptr++) = 0xD0; /* ...call dword [eax] */ \ 216 | *(ptr++) = 0x83; /* add esp,byte +0x4... */ \ 217 | *(ptr++) = 0xC4; /* ...add esp,byte +0x4 */ \ 218 | *(ptr++) = 0x04; /* ...add esp,byte +0x4 */ \ 219 | *(ptr++) = 0x07; /* pop es */ \ 220 | *(ptr++) = 0x1F; /* pop ds */ \ 221 | *(ptr++) = 0x66; /* pop bx... */ \ 222 | *(ptr++) = 0x5B; /* ...pop bx */ \ 223 | *(ptr++) = 0x66; /* pop cx... */ \ 224 | *(ptr++) = 0x59; /* ...pop cx */ \ 225 | *(ptr++) = 0x66; /* jmp word 0xaaaa:0xbbbb... */ \ 226 | *(ptr++) = 0xEA; /* ...jmp word 0xaaaa:0xbbbb */ \ 227 | const uint16 jmp16offset = (uint16) ((((uint32)ptr) - ((uint32)mmapaddr))+4); \ 228 | memcpy(ptr, &jmp16offset, 2); ptr += 2; \ 229 | const uint16 jmp16segment = (obj16.alias << 3) | 7; \ 230 | memcpy(ptr, &jmp16segment, 2); ptr += 2; \ 231 | \ 232 | /* USE16 */ \ 233 | *(ptr++) = 0x8E; /* mov ss,cx... */ \ 234 | *(ptr++) = 0xD1; /* ...mov ss,cx */ \ 235 | *(ptr++) = 0x89; /* mov sp,bx... */ \ 236 | *(ptr++) = 0xDC; /* ...mov sp,bx */ \ 237 | *(ptr++) = 0x5D; /* pop bp */ \ 238 | *(ptr++) = 0x5F; /* pop di */ \ 239 | *(ptr++) = 0x5E; /* pop si */ \ 240 | *(ptr++) = 0x5A; /* pop dx */ \ 241 | *(ptr++) = 0x59; /* pop cx */ \ 242 | *(ptr++) = 0x5B; /* pop bx */ \ 243 | *(ptr++) = 0xCA; /* retf 0x22... */ \ 244 | const uint16 argbytecount = argbytes; \ 245 | memcpy(ptr, &argbytecount, 2); ptr += 2; \ 246 | } 247 | 248 | #define LX_NATIVE_MODULE_INIT_16BIT_SUPPORT_END() { \ 249 | assert((((uint32)ptr) - ((uint32)mmapaddr)) < 0x10000); /* don't be more than 64k. */ \ 250 | if (mprotect(obj16.mapped, vsize, PROT_READ | PROT_EXEC) == -1) { \ 251 | fprintf(stderr, "mprotect() failed for 16-bit bridge code!\n"); \ 252 | munmap(obj16.mapped, vsize); \ 253 | GLoaderState.freeSelector(obj16.alias); \ 254 | obj16.mapped = obj16.addr = NULL; \ 255 | obj16.size = 0; \ 256 | obj16.alias = 0xFFFF; \ 257 | return 0; \ 258 | } \ 259 | } 260 | 261 | #define LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(typ, var) \ 262 | const typ var = *((typ *) args); args += sizeof (typ) 263 | 264 | #define LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(typ, var) \ 265 | typ var = (typ) GLoaderState.convert1616to32(*((uint32 *) args)); args += sizeof (uint32) 266 | 267 | #define LX_NATIVE_EXPORT16(fn, ord) { ord, #fn, &fn##16, &obj16 } 268 | #define LX_NATIVE_EXPORT16_DIFFERENT_NAME(fn, fnname, ord) { ord, fnname, &fn##16, &obj16 } 269 | 270 | #endif 271 | 272 | // end of os2native16.h ... 273 | 274 | -------------------------------------------------------------------------------- /native/os2types.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_OS2TYPES_H_ 10 | #define _INCL_OS2TYPES_H_ 11 | 12 | #include 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | // this doesn't do anything when compiling, but a script parses these in 19 | // the headers to generate some code. 20 | #define OS2APIINFO(...) 21 | 22 | #ifndef APIENTRY 23 | #define APIENTRY 24 | #endif 25 | 26 | #ifndef OS2EXPORT 27 | #define OS2EXPORT __attribute__((visibility("default"))) 28 | #endif 29 | 30 | #ifndef OS2API 31 | #define OS2API APIENTRY 32 | #endif 33 | 34 | // Note that we never export actual 16-bit APIs from these headers, even if 35 | // we have them marked as OS2API16. This is just for documentation's sake at 36 | // the moment. If you compile against these headers and link against an 37 | // OS2API16 function, they will be exist and operate in a linear address 38 | // space. If you call them from an LX executable, though, the system assumes 39 | // you're calling in from 16-bit code and exports something that cleans up 40 | // the details behind the scenes. 41 | // For developing against this API directly on Linux, you should assume this 42 | // works like OS/2's PowerPC port, and the same 16-bit APIs you used on x86 43 | // were made 32-bit clean by default for the new platform. 44 | #ifndef OS2API16 45 | #define OS2API16 OS2API 46 | #endif 47 | 48 | typedef uint32_t APIRET; 49 | typedef uint16_t APIRET16; 50 | typedef uint32_t APIRET32; 51 | 52 | typedef uint32_t BOOL; 53 | 54 | typedef void VOID; 55 | typedef VOID *PVOID; 56 | typedef PVOID *PPVOID; 57 | typedef char CHAR, *PCHAR; 58 | typedef uint8_t UCHAR, *PUCHAR; 59 | typedef int16_t SHORT, *PSHORT; 60 | typedef uint16_t USHORT, *PUSHORT; 61 | typedef int32_t LONG, *PLONG; 62 | typedef uint32_t ULONG, *PULONG; 63 | typedef uint32_t BOOL32, *PBOOL32; 64 | typedef int64_t LONGLONG, *PLONGLONG; 65 | typedef uint64_t ULONGLONG, *PULONGLONG; 66 | typedef uint8_t BYTE, *PBYTE; 67 | 68 | // !!! FIXME: HANDLE should either be 64-bits on x86_64, or we need to 69 | // !!! FIXME: refactor and mutex a bunch of stuff...if it has to be a 32-bit 70 | // !!! FIXME: int, it needs to be an index into a resizable array, but at the 71 | // !!! FIXME: native word size, these handles can just be pointers cast to ints. 72 | // !!! FIXME: alternately: guarantee all handles are in the bottom 4 gigabytes? 73 | typedef uint16_t SHANDLE, *PSHANDLE; 74 | typedef uint32_t LHANDLE, *PLHANDLE; 75 | typedef LHANDLE HANDLE, *PHANDLE; 76 | typedef HANDLE HMODULE, *PHMODULE; 77 | typedef HANDLE HFILE, *PHFILE; 78 | typedef HANDLE HDIR, *PHDIR; 79 | typedef HANDLE HEV, *PHEV; 80 | typedef HANDLE HMTX, *PHMTX; 81 | typedef HANDLE HQUEUE, *PHQUEUE; 82 | typedef HANDLE HPS, *PHPS; 83 | typedef HANDLE PID, *PPID; 84 | typedef HANDLE TID, *PTID; 85 | typedef SHANDLE HVIO, *PHVIO; 86 | typedef SHANDLE HKBD, *PHKBD; 87 | 88 | typedef PCHAR PSZ; 89 | typedef PCHAR PCH; 90 | 91 | typedef USHORT SEL; 92 | typedef PUSHORT PSEL; 93 | 94 | typedef int (APIENTRY *PFN)(void); 95 | 96 | typedef ULONG ERRORID; 97 | 98 | #define NULLHANDLE 0 99 | #define TRUE 1 100 | #define FALSE 0 101 | 102 | #ifdef __cplusplus 103 | } 104 | #endif 105 | 106 | #endif 107 | 108 | // end of os2types.h ... 109 | 110 | -------------------------------------------------------------------------------- /native/pmgpi-lx.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | */ 6 | 7 | /* THIS FILE IS AUTOGENERATED. DO NOT EDIT BY HAND. see lxapigen.pl */ 8 | 9 | /* This is glue code for OS/2 binaries. Native binaries don't need this. */ 10 | #if LX_LEGACY 11 | 12 | LX_NATIVE_MODULE_INIT() 13 | LX_NATIVE_EXPORT(GpiQueryTextBox, 489) 14 | LX_NATIVE_MODULE_INIT_END() 15 | 16 | #endif /* LX_LEGACY */ 17 | 18 | /* end of pmgpi-lx.h ... */ 19 | 20 | -------------------------------------------------------------------------------- /native/pmgpi.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #include "os2native.h" 10 | #include "pmgpi.h" 11 | 12 | #include "pmgpi-lx.h" 13 | 14 | BOOL GpiQueryTextBox(HPS hps, LONG lCount1, PCH pchString, LONG lCount2, PPOINTL aptlPoints) 15 | { 16 | TRACE_NATIVE("GpiQueryTextBox(%u, %d, '%s', %d, %p)", (unsigned int) hps, (int) lCount1, pchString, (int) lCount2, aptlPoints); 17 | FIXME("write me"); 18 | return 0; 19 | } // GpiQueryTextBox 20 | 21 | // end of pmgpi.c ... 22 | 23 | -------------------------------------------------------------------------------- /native/pmgpi.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_PMGPI_H_ 10 | #define _INCL_PMGPI_H_ 11 | 12 | #include "os2types.h" 13 | #include "pmwin.h" 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | OS2EXPORT BOOL OS2API GpiQueryTextBox(HPS hps, LONG lCount1, PCH pchString, LONG lCount2, PPOINTL aptlPoints) OS2APIINFO(489); 20 | 21 | #ifdef __cplusplus 22 | } 23 | #endif 24 | 25 | #endif 26 | 27 | // end of pmgpi.h ... 28 | 29 | -------------------------------------------------------------------------------- /native/pmmerge.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #include "os2native.h" 10 | #include "pmmerge.h" 11 | 12 | LX_NATIVE_MODULE_INIT() 13 | LX_NATIVE_MODULE_INIT_END() 14 | 15 | // end of pmmerge.c ... 16 | 17 | -------------------------------------------------------------------------------- /native/pmmerge.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_PMMERGE_H_ 10 | #define _INCL_PMMERGE_H_ 11 | 12 | #include "os2types.h" 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | #endif 23 | 24 | // end of pmmerge.h ... 25 | 26 | -------------------------------------------------------------------------------- /native/pmshapi.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #include "os2native.h" 10 | #include "pmshapi.h" 11 | 12 | LX_NATIVE_MODULE_INIT() 13 | LX_NATIVE_MODULE_INIT_END() 14 | 15 | // end of pmshapi.c ... 16 | 17 | -------------------------------------------------------------------------------- /native/pmshapi.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_PMSHAPI_H_ 10 | #define _INCL_PMSHAPI_H_ 11 | 12 | #include "os2types.h" 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | #endif 23 | 24 | // end of pmshapi.h ... 25 | 26 | -------------------------------------------------------------------------------- /native/pmwin-lx.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | */ 6 | 7 | /* THIS FILE IS AUTOGENERATED. DO NOT EDIT BY HAND. see lxapigen.pl */ 8 | 9 | /* This is glue code for OS/2 binaries. Native binaries don't need this. */ 10 | #if LX_LEGACY 11 | 12 | LX_NATIVE_MODULE_INIT() 13 | LX_NATIVE_EXPORT(WinBeginPaint, 703), 14 | LX_NATIVE_EXPORT(WinCreateMsgQueue, 716), 15 | LX_NATIVE_EXPORT(WinDestroyMsgQueue, 726), 16 | LX_NATIVE_EXPORT(WinDestroyWindow, 728), 17 | LX_NATIVE_EXPORT(WinEndPaint, 738), 18 | LX_NATIVE_EXPORT(WinFillRect, 743), 19 | LX_NATIVE_EXPORT(WinGetLastError, 753), 20 | LX_NATIVE_EXPORT(WinInitialize, 763), 21 | LX_NATIVE_EXPORT(WinIsWindow, 772), 22 | LX_NATIVE_EXPORT(WinIsWindowEnabled, 773), 23 | LX_NATIVE_EXPORT(WinIsWindowVisible, 775), 24 | LX_NATIVE_EXPORT(WinTerminate, 888), 25 | LX_NATIVE_EXPORT(WinPostQueueMsg, 902), 26 | LX_NATIVE_EXPORT(WinCreateStdWindow, 908), 27 | LX_NATIVE_EXPORT(WinCreateWindow, 909), 28 | LX_NATIVE_EXPORT(WinDefWindowProc, 911), 29 | LX_NATIVE_EXPORT(WinDispatchMsg, 912), 30 | LX_NATIVE_EXPORT(WinGetMsg, 915), 31 | LX_NATIVE_EXPORT(WinPostMsg, 919), 32 | LX_NATIVE_EXPORT(WinSendMsg, 920), 33 | LX_NATIVE_EXPORT(WinRegisterClass, 926) 34 | LX_NATIVE_MODULE_INIT_END() 35 | 36 | #endif /* LX_LEGACY */ 37 | 38 | /* end of pmwin-lx.h ... */ 39 | 40 | -------------------------------------------------------------------------------- /native/quecalls-lx.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | */ 6 | 7 | /* THIS FILE IS AUTOGENERATED. DO NOT EDIT BY HAND. see lxapigen.pl */ 8 | 9 | /* This is glue code for OS/2 binaries. Native binaries don't need this. */ 10 | #if LX_LEGACY 11 | 12 | LX_NATIVE_MODULE_INIT() 13 | LX_NATIVE_EXPORT(DosReadQueue, 9), 14 | LX_NATIVE_EXPORT(DosPurgeQueue, 10), 15 | LX_NATIVE_EXPORT(DosCloseQueue, 11), 16 | LX_NATIVE_EXPORT(DosQueryQueue, 12), 17 | LX_NATIVE_EXPORT(DosPeekQueue, 13), 18 | LX_NATIVE_EXPORT(DosWriteQueue, 14), 19 | LX_NATIVE_EXPORT(DosOpenQueue, 15), 20 | LX_NATIVE_EXPORT(DosCreateQueue, 16) 21 | LX_NATIVE_MODULE_INIT_END() 22 | 23 | #endif /* LX_LEGACY */ 24 | 25 | /* end of quecalls-lx.h ... */ 26 | 27 | -------------------------------------------------------------------------------- /native/quecalls.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #include "os2native.h" 10 | #include "quecalls.h" 11 | 12 | #include "quecalls-lx.h" 13 | 14 | 15 | APIRET DosCreateQueue(PHQUEUE phq, ULONG priority, PSZ pszName) 16 | { 17 | TRACE_NATIVE("DosCreateQueue(%p, %u, '%s')", phq, priority, pszName); 18 | FIXME("write me"); 19 | return ERROR_QUE_NO_MEMORY; 20 | } // DosCreateQueue 21 | 22 | APIRET DosCloseQueue(HQUEUE hq) 23 | { 24 | TRACE_NATIVE("DosCloseQueue(%u)", (uint) hq); 25 | FIXME("write me"); 26 | return ERROR_QUE_INVALID_HANDLE; 27 | } // DosCloseQueue 28 | 29 | APIRET DosOpenQueue(PPID ppid, PHQUEUE phq, PSZ pszName) 30 | { 31 | TRACE_NATIVE("DosOpenQueue(%p, %p, '%s')", ppid, phq, pszName); 32 | FIXME("write me"); 33 | return ERROR_QUE_NO_MEMORY; 34 | } // DosOpenQueue 35 | 36 | APIRET DosPeekQueue(HQUEUE hq, PREQUESTDATA pRequest, PULONG pcbData, PPVOID ppbuf, PULONG element, BOOL32 nowait, PBYTE ppriority, HEV hsem) 37 | { 38 | TRACE_NATIVE("DosPeekQueue(%u, %p, %p, %p, %p, %u, %p, %u)", (uint) hq, pRequest, pcbData, ppbuf, element, (uint) nowait, ppriority, (uint) hsem); 39 | FIXME("write me"); 40 | return ERROR_QUE_INVALID_HANDLE; 41 | } // DosPeekQueue 42 | 43 | APIRET DosPurgeQueue(HQUEUE hq) 44 | { 45 | TRACE_NATIVE("DosPurgeQueue(%u)", (uint) hq); 46 | FIXME("write me"); 47 | return ERROR_QUE_INVALID_HANDLE; 48 | } // DosCloseQueue 49 | 50 | APIRET DosQueryQueue(HQUEUE hq, PULONG pcbEntries) 51 | { 52 | TRACE_NATIVE("DosQueryQueue(%u, %p)", (uint) hq, pcbEntries); 53 | FIXME("write me"); 54 | return ERROR_QUE_INVALID_HANDLE; 55 | } // DosQueryQueue 56 | 57 | APIRET DosReadQueue(HQUEUE hq, PREQUESTDATA pRequest, PULONG pcbData, PPVOID ppbuf, ULONG element, BOOL32 wait, PBYTE ppriority, HEV hsem) 58 | { 59 | TRACE_NATIVE("DosReadQueue(%u, %p, %p, %p, %u, %u, %p, %u)", (uint) hq, pRequest, pcbData, ppbuf, (uint) element, (uint) wait, ppriority, (uint) hsem); 60 | FIXME("write me"); 61 | return ERROR_QUE_INVALID_HANDLE; 62 | } // DosReadQueue 63 | 64 | APIRET DosWriteQueue(HQUEUE hq, ULONG request, ULONG cbData, PVOID pbData, ULONG priority) 65 | { 66 | TRACE_NATIVE("DosWriteQueue(%u)", (uint) hq); 67 | FIXME("write me"); 68 | return ERROR_QUE_INVALID_HANDLE; 69 | } // DosWriteQueue 70 | 71 | // end of quecalls.c ... 72 | 73 | -------------------------------------------------------------------------------- /native/quecalls.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_QUECALLS_H_ 10 | #define _INCL_QUECALLS_H_ 11 | 12 | #include "os2types.h" 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | typedef struct 19 | { 20 | PID pid; 21 | ULONG ulData; 22 | } REQUESTDATA, *PREQUESTDATA; 23 | 24 | enum 25 | { 26 | QUE_FIFO = 0, 27 | QUE_LIFO = 1, 28 | QUE_PRIORITY = 2, 29 | QUE_NOCONVERT_ADDRESS = 0, 30 | QUE_CONVERT_ADDRESS = 4 31 | }; 32 | 33 | OS2EXPORT APIRET OS2API DosCreateQueue(PHQUEUE phq, ULONG priority, PSZ pszName) OS2APIINFO(16); 34 | OS2EXPORT APIRET OS2API DosCloseQueue(HQUEUE hq) OS2APIINFO(11); 35 | OS2EXPORT APIRET OS2API DosOpenQueue(PPID ppid, PHQUEUE phq, PSZ pszName) OS2APIINFO(15); 36 | OS2EXPORT APIRET OS2API DosPeekQueue(HQUEUE hq, PREQUESTDATA pRequest, PULONG pcbData, PPVOID ppbuf, PULONG element, BOOL32 nowait, PBYTE ppriority, HEV hsem) OS2APIINFO(13); 37 | OS2EXPORT APIRET OS2API DosPurgeQueue(HQUEUE hq) OS2APIINFO(10); 38 | OS2EXPORT APIRET OS2API DosQueryQueue(HQUEUE hq, PULONG pcbEntries) OS2APIINFO(12); 39 | OS2EXPORT APIRET OS2API DosReadQueue(HQUEUE hq, PREQUESTDATA pRequest, PULONG pcbData, PPVOID ppbuf, ULONG element, BOOL32 wait, PBYTE ppriority, HEV hsem) OS2APIINFO(9); 40 | OS2EXPORT APIRET OS2API DosWriteQueue(HQUEUE hq, ULONG request, ULONG cbData, PVOID pbData, ULONG priority) OS2APIINFO(14); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | 46 | #endif 47 | 48 | // end of quecalls.h ... 49 | 50 | -------------------------------------------------------------------------------- /native/sesmgr-lx.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | */ 6 | 7 | /* THIS FILE IS AUTOGENERATED. DO NOT EDIT BY HAND. see lxapigen.pl */ 8 | 9 | /* This is glue code for OS/2 binaries. Native binaries don't need this. */ 10 | #if LX_LEGACY 11 | 12 | static APIRET16 bridge16to32_Dos16SMSetTitle(uint8 *args) { 13 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PCHAR, title); 14 | return Dos16SMSetTitle(title); 15 | } 16 | 17 | LX_NATIVE_MODULE_16BIT_SUPPORT() 18 | LX_NATIVE_MODULE_16BIT_API(Dos16SMSetTitle) 19 | LX_NATIVE_MODULE_16BIT_SUPPORT_END() 20 | 21 | LX_NATIVE_MODULE_DEINIT({ 22 | LX_NATIVE_MODULE_DEINIT_16BIT_SUPPORT(); 23 | }) 24 | 25 | static int init16_sesmgr(void) { 26 | LX_NATIVE_MODULE_INIT_16BIT_SUPPORT() 27 | LX_NATIVE_INIT_16BIT_BRIDGE(Dos16SMSetTitle, 4) 28 | LX_NATIVE_MODULE_INIT_16BIT_SUPPORT_END() 29 | return 1; 30 | } 31 | 32 | LX_NATIVE_MODULE_INIT({ if (!init16_sesmgr()) return 0; }) 33 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(Dos16SMSetTitle, "DOSSMSETTITLE", 5), 34 | LX_NATIVE_EXPORT(DosStartSession, 37) 35 | LX_NATIVE_MODULE_INIT_END() 36 | 37 | #endif /* LX_LEGACY */ 38 | 39 | /* end of sesmgr-lx.h ... */ 40 | 41 | -------------------------------------------------------------------------------- /native/sesmgr.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #include "os2native16.h" 10 | #include "sesmgr.h" 11 | 12 | #include "sesmgr-lx.h" 13 | 14 | APIRET DosStartSession(PSTARTDATA psd, PULONG pidSession, PPID ppid) 15 | { 16 | TRACE_NATIVE("DosStartSession(%p, %p, %p)", psd, pidSession, ppid); 17 | printf("'%s', '%s', '%s'\n", psd->PgmTitle, psd->PgmName, psd->IconFile); 18 | return ERROR_NOT_ENOUGH_MEMORY; 19 | } // DosStartSession 20 | 21 | APIRET16 Dos16SMSetTitle(PCHAR title) 22 | { 23 | TRACE_NATIVE("Dos16SMSetTitle(%p)", title); 24 | return NO_ERROR; 25 | } 26 | 27 | // end of sesmgr.c ... 28 | 29 | -------------------------------------------------------------------------------- /native/sesmgr.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_SESMGR_H_ 10 | #define _INCL_SESMGR_H_ 11 | 12 | #include "os2types.h" 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | typedef struct 19 | { 20 | USHORT Length; 21 | USHORT Related; 22 | USHORT FgBg; 23 | USHORT TraceOpt; 24 | PSZ PgmTitle; 25 | PSZ PgmName; 26 | PBYTE PgmInputs; 27 | PBYTE TermQ; 28 | PBYTE Environment; 29 | USHORT InheritOpt; 30 | USHORT SessionType; 31 | PSZ IconFile; 32 | ULONG PgmHandle; 33 | USHORT PgmControl; 34 | USHORT InitXPos; 35 | USHORT InitYPos; 36 | USHORT InitXSize; 37 | USHORT InitYSize; 38 | USHORT Reserved; 39 | PSZ ObjectBuffer; 40 | ULONG ObjectBuffLen; 41 | } STARTDATA, *PSTARTDATA; 42 | 43 | OS2EXPORT APIRET OS2API DosStartSession(PSTARTDATA psd, PULONG pidSession, PPID ppid) OS2APIINFO(ord=37); 44 | OS2EXPORT APIRET16 OS2API16 Dos16SMSetTitle(PCHAR title) OS2APIINFO(ord=5,name=DOSSMSETTITLE); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif 51 | 52 | // end of sesmgr.h ... 53 | 54 | -------------------------------------------------------------------------------- /native/som.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #include "os2native.h" 10 | #include "som.h" 11 | 12 | LX_NATIVE_MODULE_INIT() 13 | LX_NATIVE_MODULE_INIT_END() 14 | 15 | // end of som.c ... 16 | 17 | -------------------------------------------------------------------------------- /native/som.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_SOM_H_ 10 | #define _INCL_SOM_H_ 11 | 12 | #include "os2types.h" 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | 22 | #endif 23 | 24 | // end of som.h ... 25 | 26 | -------------------------------------------------------------------------------- /native/tcpip32-lx.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | */ 6 | 7 | /* THIS FILE IS AUTOGENERATED. DO NOT EDIT BY HAND. see lxapigen.pl */ 8 | 9 | /* This is glue code for OS/2 binaries. Native binaries don't need this. */ 10 | #if LX_LEGACY 11 | 12 | LX_NATIVE_MODULE_INIT() 13 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_accept, "accept", 1), 14 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_bind, "bind", 2), 15 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_connect, "connect", 3), 16 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_getsockname, "getsockname", 6), 17 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_recv, "recv", 10), 18 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_os2_select, "os2_select", 12), 19 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_send, "send", 13), 20 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_setsockopt, "setsockopt", 15), 21 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_socket, "socket", 16), 22 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_soclose, "soclose", 17), 23 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_sock_errno, "sock_errno", 20), 24 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_shutdown, "shutdown", 25), 25 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_sock_init, "sock_init", 26), 26 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_select, "select", 32), 27 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_gettimeofday, "gettimeofday", 102), 28 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_inet_addr, "inet_addr", 105), 29 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_inet_ntoa, "inet_ntoa", 110), 30 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_gethostbyname, "gethostbyname", 111), 31 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_getservbyname, "getservbyname", 124), 32 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_Raccept, "Raccept", 156), 33 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_Rbind, "Rbind", 157), 34 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_Rconnect, "Rconnect", 158), 35 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_Rgetsockname, "Rgetsockname", 159), 36 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_Rlisten, "Rlisten", 160), 37 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_Rgethostbyname, "Rgethostbyname", 161), 38 | LX_NATIVE_EXPORT_DIFFERENT_NAME(OS2_htons, "htons", 205) 39 | LX_NATIVE_MODULE_INIT_END() 40 | 41 | #endif /* LX_LEGACY */ 42 | 43 | /* end of tcpip32-lx.h ... */ 44 | 45 | -------------------------------------------------------------------------------- /native/tcpip32.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #include "os2native.h" 10 | #include "tcpip32.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "tcpip32-lx.h" 24 | 25 | int OS2_sock_init(void) 26 | { 27 | TRACE_NATIVE("sock_init()"); 28 | return 1; // always succeeds. 29 | } // OS2_sock_init 30 | 31 | // !!! FIXME: currently expects you're doing IPv4 32 | static void mapOS2SockAddrIn(const OS2_sockaddr *os2addr, struct sockaddr_in *bsdaddr) 33 | { 34 | const OS2_sockaddr_in *os2addrin = (const OS2_sockaddr_in *) os2addr; 35 | memset(bsdaddr, '\0', sizeof (*bsdaddr)); 36 | bsdaddr->sin_family = AF_INET; 37 | bsdaddr->sin_port = os2addrin->sin_port; 38 | bsdaddr->sin_addr.s_addr = os2addrin->sin_addr.s_addr; 39 | } // mapOS2SockAddrIn 40 | 41 | // !!! FIXME: currently expects you're doing IPv4 42 | static void mapBSDSockAddrIn(const struct sockaddr_in *bsdaddr, OS2_sockaddr *os2addr) 43 | { 44 | OS2_sockaddr_in *os2addrin = (OS2_sockaddr_in *) os2addr; 45 | memset(os2addrin, '\0', sizeof (*os2addrin)); 46 | os2addrin->sin_family = OS2_AF_INET; 47 | os2addrin->sin_port = bsdaddr->sin_port; 48 | os2addrin->sin_addr.s_addr = bsdaddr->sin_addr.s_addr; 49 | } // mapBSDSockAddrIn 50 | 51 | static int mapOS2MsgFlags(const int os2flags) 52 | { 53 | int bsdflags = 0; 54 | 55 | #define MAPSOCKFLAGS(f) if (os2flags & OS2_##f) { bsdflags |= f; } 56 | MAPSOCKFLAGS(MSG_OOB); 57 | MAPSOCKFLAGS(MSG_PEEK); 58 | MAPSOCKFLAGS(MSG_DONTROUTE); 59 | MAPSOCKFLAGS(MSG_EOR); 60 | MAPSOCKFLAGS(MSG_TRUNC); 61 | MAPSOCKFLAGS(MSG_CTRUNC); 62 | MAPSOCKFLAGS(MSG_WAITALL); 63 | MAPSOCKFLAGS(MSG_DONTWAIT); 64 | #undef MAPSOCKFLAGS 65 | 66 | // !!! FIXME: no such flag on Linux 67 | //MAPSOCKFLAGS(MSG_FULLREAD); 68 | 69 | return bsdflags; 70 | } // mapOS2MsgFlags 71 | 72 | int OS2_recv(int sock, void *buf, size_t len, int os2flags) 73 | { 74 | TRACE_NATIVE("recv(%d, %p, %d, %d)", sock, buf, (int) len, os2flags); 75 | FIXME("this should fail if not a socket"); // otherwise you might be a file descriptor... 76 | return recv(sock, buf, len, mapOS2MsgFlags(os2flags)); 77 | } // OS2_recv 78 | 79 | int OS2_connect(int sock, const struct OS2_sockaddr *os2addr, int addrlen) 80 | { 81 | TRACE_NATIVE("connect(%d, %p, %d)", sock, os2addr, addrlen); 82 | 83 | FIXME("this should fail if not a socket"); // otherwise you might be a file descriptor... 84 | 85 | if (os2addr->sa_family != OS2_AF_INET) { 86 | FIXME("currently demands IPv4 socket"); 87 | return -1; 88 | } 89 | 90 | struct sockaddr_in bsdaddr; 91 | mapOS2SockAddrIn(os2addr, &bsdaddr); 92 | return connect(sock, &bsdaddr, (socklen_t) sizeof (bsdaddr)); 93 | } // OS2_connect 94 | 95 | int OS2_shutdown(int sock, int kind) 96 | { 97 | TRACE_NATIVE("shutdown(%d, %d)", sock, kind); 98 | FIXME("this should fail if not a socket"); // otherwise you might be a file descriptor... 99 | return shutdown(sock, kind); 100 | } // OS2_shutdown 101 | 102 | int OS2_socket(int os2family, int os2socktype, int protocol) 103 | { 104 | TRACE_NATIVE("socket(%d, %d, %d)", os2family, os2socktype, protocol); 105 | if (os2family != OS2_AF_INET) { 106 | FIXME("currently demands IPv4 socket"); 107 | return -1; 108 | } 109 | 110 | if (protocol != 0) { 111 | FIXME("Only protocol 0 supported at the moment"); 112 | return -1; 113 | } 114 | 115 | int bsdsocktype; 116 | if (os2socktype == OS2_SOCK_STREAM) { 117 | bsdsocktype = SOCK_STREAM; 118 | } else if (os2socktype == OS2_SOCK_DGRAM) { 119 | bsdsocktype = SOCK_DGRAM; 120 | } else { 121 | FIXME("Only SOCK_STREAM and SOCK_DGRAM supported at the moment"); 122 | return -1; 123 | } 124 | 125 | return socket(AF_INET, bsdsocktype, 0); 126 | } // OS2_socket 127 | 128 | ssize_t OS2_send(int sock, const void *buf, size_t len, int os2flags) 129 | { 130 | TRACE_NATIVE("send(%d, %p, %d, %d)", sock, buf, (int) len, os2flags); 131 | FIXME("this should fail if not a socket"); // otherwise you might be a file descriptor... 132 | return send(sock, buf, len, mapOS2MsgFlags(os2flags)); 133 | } // OS2_send 134 | 135 | int OS2_soclose(int sock) 136 | { 137 | TRACE_NATIVE("soclose(%d)", sock); 138 | FIXME("this should fail if not a socket"); // otherwise you might close a file descriptor... 139 | return close(sock); 140 | } // OS2_soclose 141 | 142 | int OS2_sock_errno(void) 143 | { 144 | TRACE_NATIVE("sock_errno()"); 145 | FIXME("this should cache errno when an OS/2 socket function fails"); 146 | return errno; 147 | } // OS2_sock_errno 148 | 149 | unsigned long OS2_inet_addr(const char *name) 150 | { 151 | TRACE_NATIVE("inet_addr('%s')", name); 152 | return inet_addr(name); 153 | } // OS2_inet_addr 154 | 155 | struct OS2_hostent *OS2_gethostbyname(const char *name) 156 | { 157 | TRACE_NATIVE("gethostbyname('%s')", name); 158 | struct hostent *hent = gethostbyname(name); 159 | return (OS2_hostent *) hent; // these happen to match up between Linux and OS/2. 160 | } // OS2_gethostbyname 161 | 162 | unsigned short OS2_htons(unsigned short val) 163 | { 164 | TRACE_NATIVE("htons(%u)", (unsigned int) val); 165 | return htons(val); 166 | } // OS2_htons 167 | 168 | char *OS2_inet_ntoa(struct OS2_in_addr os2inaddr) 169 | { 170 | TRACE_NATIVE("inet_ntoa(%u)", (unsigned int) os2inaddr.s_addr); 171 | struct in_addr bsdaddr; 172 | bsdaddr.s_addr = os2inaddr.s_addr; 173 | return inet_ntoa(bsdaddr); 174 | } // OS2_inet_ntoa 175 | 176 | struct OS2_servent *OS2_getservbyname(const char *name, const char *proto) 177 | { 178 | TRACE_NATIVE("getservbyname('%s', '%s')", name, proto); 179 | struct servent *sent = getservbyname(name, proto); 180 | return (OS2_servent *) sent; // these happen to match up between Linux and OS/2. 181 | } // OS2_getservbyname 182 | 183 | static void mapOS2FdSet(const OS2_fd_set *os2set, fd_set *bsdset) 184 | { 185 | FD_ZERO(bsdset); 186 | const int total = os2set->fd_count; 187 | for (int i = 0; i < total; i++) { 188 | FD_SET(os2set->fd_array[i], bsdset); 189 | } 190 | } // mapOS2FdSet 191 | 192 | int OS2_select(int ndfs, OS2_fd_set *os2readfds, OS2_fd_set *os2writefds, OS2_fd_set *os2errorfds, OS2_timeval *os2timeout) 193 | { 194 | TRACE_NATIVE("select(%d, %p, %p, %p, %p)", ndfs, os2readfds, os2writefds, os2errorfds, os2timeout); 195 | #define MAPFDS(t) \ 196 | fd_set bsd##t##fds; \ 197 | fd_set *t##fds = NULL; \ 198 | if (os2##t##fds) { \ 199 | t##fds = &bsd##t##fds; \ 200 | mapOS2FdSet(os2##t##fds, t##fds); \ 201 | } 202 | MAPFDS(read); 203 | MAPFDS(write); 204 | MAPFDS(error); 205 | #undef MAPFDS 206 | 207 | struct timeval bsdtv; 208 | struct timeval *pbsdtv = NULL; 209 | if (os2timeout) { 210 | pbsdtv = &bsdtv; 211 | bsdtv.tv_sec = os2timeout->tv_sec; 212 | bsdtv.tv_usec = os2timeout->tv_usec; 213 | } 214 | const int rc = select(ndfs, readfds, writefds, errorfds, pbsdtv); 215 | FIXME("fill in OS/2 fds"); 216 | return rc; 217 | } // OS2_select 218 | 219 | int OS2_os2_select(int *socks, int noreads, int nowrites, int noexcept, long timeout) 220 | { 221 | TRACE_NATIVE("os2_select(%p, %d, %d, %d, %d)", socks, noreads, nowrites, noexcept, (int) timeout); 222 | const int nfds = noreads + nowrites + noexcept; 223 | struct pollfd *fds = (struct pollfd *) alloca(sizeof (struct pollfd) * nfds); 224 | struct pollfd *origfds = fds; 225 | for (int i = 0; i < noreads; i++) { 226 | fds->fd = *(socks++); 227 | fds->events = POLLIN; 228 | fds++; 229 | } 230 | 231 | for (int i = 0; i < nowrites; i++) { 232 | fds->fd = *(socks++); 233 | fds->events = POLLOUT; 234 | fds++; 235 | } 236 | 237 | for (int i = 0; i < noexcept; i++) { 238 | fds->fd = *(socks++); 239 | fds->events = POLLERR; 240 | fds++; 241 | } 242 | 243 | return poll(origfds, nfds, timeout * 1000); 244 | } // OS2_os2_select 245 | 246 | int OS2_getsockname(int sock, OS2_sockaddr *os2name, int *os2namelen) 247 | { 248 | TRACE_NATIVE("getsockname(%d, %p, %p)", sock, os2name, os2namelen); 249 | 250 | struct sockaddr_in bsdaddr; 251 | socklen_t namelen = sizeof (bsdaddr); 252 | const int rc = getsockname(sock, &bsdaddr, &namelen); 253 | if (rc == -1) { 254 | return -1; 255 | } else if (bsdaddr.sin_family != AF_INET) { 256 | FIXME("this only deals with IPv4 at the moment"); 257 | return -1; 258 | } else if (*os2namelen < sizeof (OS2_sockaddr_in)) { 259 | return -1; 260 | } 261 | 262 | mapBSDSockAddrIn(&bsdaddr, os2name); 263 | *os2namelen = sizeof (OS2_sockaddr_in); 264 | return rc; 265 | } // OS2_getsockname 266 | 267 | int OS2_bind(int sock, const OS2_sockaddr *os2name, int os2namelen) 268 | { 269 | TRACE_NATIVE("bind(%d, %p, %d)", sock, os2name, os2namelen); 270 | struct sockaddr_in bsdaddr; 271 | mapOS2SockAddrIn(os2name, &bsdaddr); 272 | return bind(sock, (struct sockaddr *) &bsdaddr, sizeof (bsdaddr)); 273 | } // OS2_bind 274 | 275 | int OS2_listen(int sock, int backlog) 276 | { 277 | TRACE_NATIVE("listen(%d, %d)", sock, backlog); 278 | return listen(sock, backlog); 279 | } // OS2_listen 280 | 281 | int OS2_accept(int sock, OS2_sockaddr *os2name, int *os2namelen) 282 | { 283 | TRACE_NATIVE("bind(%d, %p, %p)", sock, os2name, os2namelen); 284 | struct sockaddr_in bsdaddr; 285 | socklen_t bsdaddrlen = sizeof (bsdaddr); 286 | const int retval = accept(sock, (struct sockaddr *) &bsdaddr, &bsdaddrlen); 287 | 288 | if (os2name != NULL) { 289 | mapBSDSockAddrIn(&bsdaddr, os2name); 290 | } 291 | 292 | if (os2namelen != NULL) { 293 | *os2namelen = sizeof (OS2_sockaddr_in); 294 | } 295 | 296 | return retval; 297 | } // OS2_accept 298 | 299 | static int mapOS2SocketOption(const int os2name) 300 | { 301 | switch (os2name) { 302 | #define MAPSOOPT(f) case OS2_##f: return f 303 | MAPSOOPT(SO_DEBUG); 304 | MAPSOOPT(SO_ACCEPTCONN); 305 | MAPSOOPT(SO_REUSEADDR); 306 | MAPSOOPT(SO_KEEPALIVE); 307 | MAPSOOPT(SO_DONTROUTE); 308 | MAPSOOPT(SO_BROADCAST); 309 | //MAPSOOPT(SO_USELOOPBACK); 310 | MAPSOOPT(SO_LINGER); 311 | MAPSOOPT(SO_OOBINLINE); 312 | //MAPSOOPT(SO_L_BROADCAST); 313 | //MAPSOOPT(SO_RCV_SHUTDOWN); 314 | //MAPSOOPT(SO_SND_SHUTDOWN); 315 | MAPSOOPT(SO_REUSEPORT); 316 | //MAPSOOPT(SO_TTCP); 317 | MAPSOOPT(SO_SNDBUF); 318 | MAPSOOPT(SO_RCVBUF); 319 | MAPSOOPT(SO_SNDLOWAT); 320 | MAPSOOPT(SO_RCVLOWAT); 321 | MAPSOOPT(SO_SNDTIMEO); 322 | MAPSOOPT(SO_RCVTIMEO); 323 | MAPSOOPT(SO_ERROR); 324 | MAPSOOPT(SO_TYPE); 325 | //MAPSOOPT(SO_OPTIONS); 326 | #undef MAPSOOPT 327 | default: break; 328 | } 329 | 330 | FIXME("unsupported OS/2 socket option"); 331 | return 0; 332 | } // mapOS2SocketOption 333 | 334 | int OS2_setsockopt(int sock, int os2level, int os2name, const void *value, int len) 335 | { 336 | const int bsdname = mapOS2SocketOption(os2name); 337 | const int bsdlevel = SOL_SOCKET; 338 | if (!bsdname) { 339 | return -1; 340 | } else if (os2level != OS2_SOL_SOCKET) { 341 | return -1; 342 | } 343 | return setsockopt(sock, bsdlevel, bsdname, value, len); 344 | } // OS2_setsockopt 345 | 346 | int OS2_gettimeofday(OS2_timeval *os2tv, OS2_timezone *os2tz) 347 | { 348 | struct timeval bsdtv; 349 | struct timezone bsdtz; 350 | const int retval = gettimeofday(&bsdtv, &bsdtz); 351 | 352 | if (os2tv) { 353 | os2tv->tv_sec = bsdtv.tv_sec; 354 | os2tv->tv_usec = bsdtv.tv_usec; 355 | } 356 | 357 | if (os2tz) { 358 | os2tz->tz_minuteswest = bsdtz.tz_minuteswest; 359 | os2tz->tz_dsttime = bsdtz.tz_dsttime; 360 | } 361 | 362 | return retval; 363 | } // OS2_gettimeofday 364 | 365 | // SOCKS support... 366 | 367 | int OS2_Rgetsockname(int sock, OS2_sockaddr *os2name, int *os2namelen) 368 | { 369 | // !!! FIXME: this doesn't talk to a SOCKS proxy at all. 370 | TRACE_NATIVE("Rgetsockname(%d, %p, %p)", sock, os2name, os2namelen); 371 | return OS2_getsockname(sock, os2name, os2namelen); 372 | } // OS2_Rgetsockname 373 | 374 | int OS2_Rbind(int sock, OS2_sockaddr *os2name, int os2namelen, OS2_sockaddr *os2remote) 375 | { 376 | // !!! FIXME: this doesn't talk to a SOCKS proxy at all. 377 | TRACE_NATIVE("Rbind(%d, %p, %d, %p)", sock, os2name, os2namelen, os2remote); 378 | return OS2_bind(sock, os2name, os2namelen); 379 | } // OS2_Rbind 380 | 381 | int OS2_Raccept(int sock, OS2_sockaddr *os2name, int *os2namelen) 382 | { 383 | // !!! FIXME: this doesn't talk to a SOCKS proxy at all. 384 | TRACE_NATIVE("Raccept(%d, %p, %p)", sock, os2name, os2namelen); 385 | return OS2_accept(sock, os2name, os2namelen); 386 | } // OS2_Raccept 387 | 388 | int OS2_Rconnect(int sock, const OS2_sockaddr *os2name, int os2namelen) 389 | { 390 | // !!! FIXME: this doesn't talk to a SOCKS proxy at all. 391 | TRACE_NATIVE("Rconnect(%d, %p, %d)", sock, os2name, os2namelen); 392 | return OS2_connect(sock, os2name, os2namelen); 393 | } // OS2_Rconnect 394 | 395 | int OS2_Rlisten(int sock, int backlog) 396 | { 397 | // !!! FIXME: this doesn't talk to a SOCKS proxy at all. 398 | TRACE_NATIVE("Rlisten(%d, %d)", sock, backlog); 399 | return OS2_listen(sock, backlog); 400 | } // OS2_Rlisten 401 | 402 | OS2_hostent *OS2_Rgethostbyname(const char *name) 403 | { 404 | // !!! FIXME: this doesn't talk to a SOCKS proxy at all. 405 | TRACE_NATIVE("Rgethostbyname('%s')", name); 406 | return OS2_gethostbyname(name); 407 | } // OS2_Rgethostbyname 408 | 409 | // end of tcpip32.c ... 410 | 411 | -------------------------------------------------------------------------------- /native/tcpip32.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_TCPIP32_H_ 10 | #define _INCL_TCPIP32_H_ 11 | 12 | #include "os2types.h" 13 | #include // !!! FIXME: don't use size_t in here. 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | // These are (mostly) the same symbols as BSD sockets, so to prevent conflicts 20 | // with the _actual_ C runtime on the host, we name them OS2_*. The LX 21 | // loader exports them with the correct names. If you're recompiling an 22 | // OS/2 app and using this for API support, just use real BSD sockets 23 | // instead. 24 | 25 | // !!! FIXME: lots of "int" and such in here that should probably be int32, etc. 26 | 27 | #define OS2_MSG_OOB 0x1 28 | #define OS2_MSG_PEEK 0x2 29 | #define OS2_MSG_DONTROUTE 0x4 30 | #define OS2_MSG_FULLREAD 0x8 31 | #define OS2_MSG_EOR 0x10 32 | #define OS2_MSG_TRUNC 0x20 33 | #define OS2_MSG_CTRUNC 0x40 34 | #define OS2_MSG_WAITALL 0x80 35 | #define OS2_MSG_DONTWAIT 0x100 36 | 37 | #define OS2_AF_INET 2 38 | 39 | #define OS2_SOCK_STREAM 1 40 | #define OS2_SOCK_DGRAM 2 41 | 42 | #define OS2_SOL_SOCKET 0xffff 43 | 44 | #define OS2_SO_DEBUG 0x0001 45 | #define OS2_SO_ACCEPTCONN 0x0002 46 | #define OS2_SO_REUSEADDR 0x0004 47 | #define OS2_SO_KEEPALIVE 0x0008 48 | #define OS2_SO_DONTROUTE 0x0010 49 | #define OS2_SO_BROADCAST 0x0020 50 | #define OS2_SO_USELOOPBACK 0x0040 51 | #define OS2_SO_LINGER 0x0080 52 | #define OS2_SO_OOBINLINE 0x0100 53 | #define OS2_SO_L_BROADCAST 0x0200 54 | #define OS2_SO_RCV_SHUTDOWN 0x0400 55 | #define OS2_SO_SND_SHUTDOWN 0x0800 56 | #define OS2_SO_REUSEPORT 0x1000 57 | #define OS2_SO_TTCP 0x2000 58 | #define OS2_SO_SNDBUF 0x1001 59 | #define OS2_SO_RCVBUF 0x1002 60 | #define OS2_SO_SNDLOWAT 0x1003 61 | #define OS2_SO_RCVLOWAT 0x1004 62 | #define OS2_SO_SNDTIMEO 0x1005 63 | #define OS2_SO_RCVTIMEO 0x1006 64 | #define OS2_SO_ERROR 0x1007 65 | #define OS2_SO_TYPE 0x1008 66 | #define OS2_SO_OPTIONS 0x1010 67 | 68 | 69 | #pragma pack(push, 1) 70 | typedef struct OS2_sockaddr 71 | { 72 | uint8_t sa_len; 73 | uint8_t sa_family; 74 | char sa_data[14]; 75 | } OS2_sockaddr; 76 | 77 | typedef struct OS2_in_addr 78 | { 79 | uint32_t s_addr; 80 | } OS2_in_addr; 81 | 82 | typedef struct OS2_sockaddr_in 83 | { 84 | uint8_t sin_len; 85 | uint8_t sin_family; 86 | uint16_t sin_port; 87 | struct OS2_in_addr sin_addr; 88 | char sin_zero[8]; 89 | } OS2_sockaddr_in; 90 | 91 | typedef struct OS2_hostent 92 | { 93 | char *h_name; /* official name of host */ 94 | char **h_aliases; /* alias list */ 95 | int h_addrtype; /* host address type */ 96 | int h_length; /* length of address */ 97 | char **h_addr_list; /* list of addresses from name server */ 98 | } OS2_hostent; 99 | 100 | typedef struct OS2_servent 101 | { 102 | char *s_name; 103 | char **s_aliases; 104 | int s_port; 105 | char *s_proto; 106 | } OS2_servent; 107 | 108 | #define OS2_FD_SETSIZE 64 109 | typedef struct OS2_fd_set 110 | { 111 | uint16_t fd_count; 112 | uint16_t padding; 113 | int fd_array[OS2_FD_SETSIZE]; 114 | } OS2_fd_set; 115 | 116 | typedef struct OS2_timeval 117 | { 118 | int32_t tv_sec; 119 | int32_t tv_usec; 120 | } OS2_timeval; 121 | 122 | typedef struct OS2_timezone 123 | { 124 | int32_t tz_minuteswest; 125 | int32_t tz_dsttime; 126 | } OS2_timezone; 127 | #pragma pack(pop) 128 | 129 | OS2EXPORT int OS2API OS2_sock_init(void) OS2APIINFO(ord=26,name=sock_init); 130 | OS2EXPORT int OS2API OS2_recv(int sock, void *buf, size_t len, int os2flags) OS2APIINFO(ord=10,name=recv); 131 | OS2EXPORT int OS2API OS2_connect(int sock, const OS2_sockaddr *os2addr, int addrlen) OS2APIINFO(ord=3,name=connect); 132 | OS2EXPORT int OS2API OS2_shutdown(int sock, int kind) OS2APIINFO(ord=25,name=shutdown); 133 | OS2EXPORT int OS2API OS2_socket(int family, int os2socktype, int protocol) OS2APIINFO(ord=16,name=socket); 134 | OS2EXPORT ssize_t OS2API OS2_send(int sock, const void *buf, size_t len, int os2flags) OS2APIINFO(ord=13,name=send); 135 | OS2EXPORT int OS2API OS2_soclose(int sock) OS2APIINFO(ord=17,name=soclose); 136 | OS2EXPORT int OS2API OS2_sock_errno(void) OS2APIINFO(ord=20,name=sock_errno); 137 | OS2EXPORT unsigned long OS2API OS2_inet_addr(const char *name) OS2APIINFO(ord=105,name=inet_addr); 138 | OS2EXPORT OS2_hostent * OS2API OS2_gethostbyname(const char *name) OS2APIINFO(ord=111,name=gethostbyname); 139 | OS2EXPORT unsigned short OS2API OS2_htons(unsigned short val) OS2APIINFO(ord=205,name=htons); 140 | OS2EXPORT char * OS2API OS2_inet_ntoa(OS2_in_addr os2inaddr) OS2APIINFO(ord=110,name=inet_ntoa); 141 | OS2EXPORT OS2_servent * OS2API OS2_getservbyname(const char *name, const char *proto) OS2APIINFO(ord=124,name=getservbyname); 142 | OS2EXPORT int OS2API OS2_select(int sock, OS2_fd_set *readfds, OS2_fd_set *writefds, OS2_fd_set *errorfds, OS2_timeval *timeout) OS2APIINFO(ord=32,name=select); 143 | OS2EXPORT int OS2API OS2_os2_select(int *socks, int noreads, int nowrites, int noexcept, long timeout) OS2APIINFO(ord=12,name=os2_select); 144 | OS2EXPORT int OS2API OS2_getsockname(int sock, OS2_sockaddr *os2name, int *namelen) OS2APIINFO(ord=6,name=getsockname); 145 | OS2EXPORT int OS2API OS2_setsockopt(int sock, int os2level, int os2name, const void *value, int len) OS2APIINFO(ord=15,name=setsockopt); 146 | OS2EXPORT int OS2API OS2_bind(int sock, const OS2_sockaddr *os2name, int os2namelen) OS2APIINFO(ord=2,name=bind); 147 | OS2EXPORT int OS2API OS2_accept(int sock, OS2_sockaddr *os2name, int *os2namelen) OS2APIINFO(ord=1,name=accept); 148 | OS2EXPORT int OS2API OS2_Rgetsockname(int sock, OS2_sockaddr *os2name, int *namelen) OS2APIINFO(ord=159,name=Rgetsockname); 149 | OS2EXPORT int OS2API OS2_Rbind(int sock, OS2_sockaddr *os2name, int os2namelen, OS2_sockaddr *os2remote) OS2APIINFO(ord=157,name=Rbind); 150 | OS2EXPORT int OS2API OS2_Raccept(int sock, OS2_sockaddr *os2name, int *os2namelen) OS2APIINFO(ord=156,name=Raccept); 151 | OS2EXPORT int OS2API OS2_Rconnect(int sock, const OS2_sockaddr *os2name, int os2namelen) OS2APIINFO(ord=158,name=Rconnect); 152 | OS2EXPORT int OS2API OS2_Rlisten(int sock, int backlog) OS2APIINFO(ord=160,name=Rlisten); 153 | OS2EXPORT OS2_hostent * OS2API OS2_Rgethostbyname(const char *name) OS2APIINFO(ord=161,name=Rgethostbyname); 154 | OS2EXPORT int OS2API OS2_gettimeofday(OS2_timeval *os2tv, OS2_timezone *os2tz) OS2APIINFO(ord=102,name=gettimeofday); 155 | 156 | #ifdef __cplusplus 157 | } 158 | #endif 159 | 160 | #endif 161 | 162 | // end of tcpip32.h ... 163 | -------------------------------------------------------------------------------- /native/viocalls-lx.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | */ 6 | 7 | /* THIS FILE IS AUTOGENERATED. DO NOT EDIT BY HAND. see lxapigen.pl */ 8 | 9 | /* This is glue code for OS/2 binaries. Native binaries don't need this. */ 10 | #if LX_LEGACY 11 | 12 | static APIRET16 bridge16to32_VioScrollUp(uint8 *args) { 13 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(HVIO, hvio); 14 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PBYTE, pCell); 15 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, cbLines); 16 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, usRightCol); 17 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, usBotRow); 18 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, usLeftCol); 19 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, usTopRow); 20 | return VioScrollUp(usTopRow, usLeftCol, usBotRow, usRightCol, cbLines, pCell, hvio); 21 | } 22 | 23 | static APIRET16 bridge16to32_VioGetCurPos(uint8 *args) { 24 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(HVIO, hvio); 25 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PUSHORT, pusColumn); 26 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PUSHORT, pusRow); 27 | return VioGetCurPos(pusRow, pusColumn, hvio); 28 | } 29 | 30 | static APIRET16 bridge16to32_VioWrtCellStr(uint8 *args) { 31 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(HVIO, hvio); 32 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, usColumn); 33 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, usRow); 34 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, cb); 35 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PCH, pchCellStr); 36 | return VioWrtCellStr(pchCellStr, cb, usRow, usColumn, hvio); 37 | } 38 | 39 | static APIRET16 bridge16to32_VioSetCurPos(uint8 *args) { 40 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(HVIO, hvio); 41 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, usColumn); 42 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, usRow); 43 | return VioSetCurPos(usRow, usColumn, hvio); 44 | } 45 | 46 | static APIRET16 bridge16to32_VioGetMode(uint8 *args) { 47 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(HVIO, hvio); 48 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PVIOMODEINFO, pvioModeInfo); 49 | return VioGetMode(pvioModeInfo, hvio); 50 | } 51 | 52 | static APIRET16 bridge16to32_VioReadCellStr(uint8 *args) { 53 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(HVIO, hvio); 54 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, usColumn); 55 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, usRow); 56 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PUSHORT, pcb); 57 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PCH, pchCellStr); 58 | return VioReadCellStr(pchCellStr, pcb, usRow, usColumn, hvio); 59 | } 60 | 61 | static APIRET16 bridge16to32_VioGetCurType(uint8 *args) { 62 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(HVIO, hvio); 63 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PVIOCURSORINFO, pvioCursorInfo); 64 | return VioGetCurType(pvioCursorInfo, hvio); 65 | } 66 | 67 | static APIRET16 bridge16to32_VioGetBuf(uint8 *args) { 68 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(HVIO, hvio); 69 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PUSHORT, pcbLVB); 70 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PULONG, pLVB); 71 | return VioGetBuf(pLVB, pcbLVB, hvio); 72 | } 73 | 74 | static APIRET16 bridge16to32_VioSetCurType(uint8 *args) { 75 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(HVIO, hvio); 76 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PVIOCURSORINFO, pvioCursorInfo); 77 | return VioSetCurType(pvioCursorInfo, hvio); 78 | } 79 | 80 | static APIRET16 bridge16to32_VioWrtCharStrAtt(uint8 *args) { 81 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(HVIO, hvio); 82 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PBYTE, pAttr); 83 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, usColumn); 84 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, usRow); 85 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, cb); 86 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PCH, pch); 87 | return VioWrtCharStrAtt(pch, cb, usRow, usColumn, pAttr, hvio); 88 | } 89 | 90 | static APIRET16 bridge16to32_VioWrtNCell(uint8 *args) { 91 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(HVIO, hvio); 92 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, usColumn); 93 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, usRow); 94 | LX_NATIVE_MODULE_16BIT_BRIDGE_ARG(USHORT, cb); 95 | LX_NATIVE_MODULE_16BIT_BRIDGE_PTRARG(PBYTE, pCell); 96 | return VioWrtNCell(pCell, cb, usRow, usColumn, hvio); 97 | } 98 | 99 | LX_NATIVE_MODULE_16BIT_SUPPORT() 100 | LX_NATIVE_MODULE_16BIT_API(VioScrollUp) 101 | LX_NATIVE_MODULE_16BIT_API(VioGetCurPos) 102 | LX_NATIVE_MODULE_16BIT_API(VioWrtCellStr) 103 | LX_NATIVE_MODULE_16BIT_API(VioSetCurPos) 104 | LX_NATIVE_MODULE_16BIT_API(VioGetMode) 105 | LX_NATIVE_MODULE_16BIT_API(VioReadCellStr) 106 | LX_NATIVE_MODULE_16BIT_API(VioGetCurType) 107 | LX_NATIVE_MODULE_16BIT_API(VioGetBuf) 108 | LX_NATIVE_MODULE_16BIT_API(VioSetCurType) 109 | LX_NATIVE_MODULE_16BIT_API(VioWrtCharStrAtt) 110 | LX_NATIVE_MODULE_16BIT_API(VioWrtNCell) 111 | LX_NATIVE_MODULE_16BIT_SUPPORT_END() 112 | 113 | LX_NATIVE_MODULE_DEINIT({ 114 | LX_NATIVE_MODULE_DEINIT_16BIT_SUPPORT(); 115 | }) 116 | 117 | static int init16_viocalls(void) { 118 | LX_NATIVE_MODULE_INIT_16BIT_SUPPORT() 119 | LX_NATIVE_INIT_16BIT_BRIDGE(VioScrollUp, 16) 120 | LX_NATIVE_INIT_16BIT_BRIDGE(VioGetCurPos, 10) 121 | LX_NATIVE_INIT_16BIT_BRIDGE(VioWrtCellStr, 12) 122 | LX_NATIVE_INIT_16BIT_BRIDGE(VioSetCurPos, 6) 123 | LX_NATIVE_INIT_16BIT_BRIDGE(VioGetMode, 6) 124 | LX_NATIVE_INIT_16BIT_BRIDGE(VioReadCellStr, 14) 125 | LX_NATIVE_INIT_16BIT_BRIDGE(VioGetCurType, 6) 126 | LX_NATIVE_INIT_16BIT_BRIDGE(VioGetBuf, 10) 127 | LX_NATIVE_INIT_16BIT_BRIDGE(VioSetCurType, 6) 128 | LX_NATIVE_INIT_16BIT_BRIDGE(VioWrtCharStrAtt, 16) 129 | LX_NATIVE_INIT_16BIT_BRIDGE(VioWrtNCell, 12) 130 | LX_NATIVE_MODULE_INIT_16BIT_SUPPORT_END() 131 | return 1; 132 | } 133 | 134 | LX_NATIVE_MODULE_INIT({ if (!init16_viocalls()) return 0; }) 135 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(VioScrollUp, "VIOSCROLLUP", 7), 136 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(VioGetCurPos, "VIOGETCURPOS", 9), 137 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(VioWrtCellStr, "VIOWRTCELLSTR", 10), 138 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(VioSetCurPos, "VIOSETCURPOS", 15), 139 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(VioGetMode, "VIOGETMODE", 21), 140 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(VioReadCellStr, "VIOREADCELLSTR", 24), 141 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(VioGetCurType, "VIOGETCURTYPE", 27), 142 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(VioGetBuf, "VIOGETBUF", 31), 143 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(VioSetCurType, "VIOSETCURTYPE", 32), 144 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(VioWrtCharStrAtt, "VIOWRTCHARSTRATT", 48), 145 | LX_NATIVE_EXPORT16_DIFFERENT_NAME(VioWrtNCell, "VIOWRTNCELL", 52) 146 | LX_NATIVE_MODULE_INIT_END() 147 | 148 | #endif /* LX_LEGACY */ 149 | 150 | /* end of viocalls-lx.h ... */ 151 | 152 | -------------------------------------------------------------------------------- /native/viocalls.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #include "os2native16.h" 10 | #include "viocalls.h" 11 | 12 | // os2types.h defines these, but so does curses. 13 | #undef TRUE 14 | #undef FALSE 15 | 16 | #include 17 | #include 18 | 19 | // CMake searches for a whole bunch of different possible curses includes 20 | #if defined(HAVE_NCURSESW_NCURSES_H) 21 | #include 22 | #elif defined(HAVE_NCURSESW_CURSES_H) 23 | #include 24 | #elif defined(HAVE_NCURSESW_H) 25 | #include 26 | #elif defined(HAVE_CURSES_H) 27 | #include 28 | #else 29 | #error ncurses gui enabled, but no known header file found 30 | #endif 31 | 32 | #include 33 | 34 | #include "viocalls-lx.h" 35 | 36 | enum 37 | { 38 | VIOATTR_BACK_BLACK = 0x00, 39 | VIOATTR_BACK_BLUE = 0x10, 40 | VIOATTR_BACK_GREEN = 0x20, 41 | VIOATTR_BACK_CYAN = 0x30, 42 | VIOATTR_BACK_RED = 0x40, 43 | VIOATTR_BACK_MAGENTA = 0x50, 44 | VIOATTR_BACK_YELLOW = 0x60, 45 | VIOATTR_BACK_BROWN = 0x60, 46 | VIOATTR_BACK_WHITE = 0x70, 47 | 48 | VIOATTR_FORE_BLACK = 0x00, 49 | VIOATTR_FORE_BLUE = 0x01, 50 | VIOATTR_FORE_GREEN = 0x02, 51 | VIOATTR_FORE_CYAN = 0x03, 52 | VIOATTR_FORE_RED = 0x04, 53 | VIOATTR_FORE_MAGENTA = 0x05, 54 | VIOATTR_FORE_YELLOW = 0x06, 55 | VIOATTR_FORE_BROWN = 0x06, 56 | VIOATTR_FORE_WHITE = 0x07, 57 | 58 | VIOATTR_INTENSITY = 0x08, 59 | VIOATTR_BLINK = 0x80 60 | }; 61 | 62 | 63 | static uint16 *vio_buffer = NULL; 64 | static uint16 vio_scrw, vio_scrh; 65 | static uint16 vio_curx, vio_cury; 66 | static VIOCURSORINFO vio_cursorinfo; 67 | 68 | static int initNcurses(void) 69 | { 70 | if (vio_buffer != NULL) 71 | return 1; 72 | 73 | setlocale(LC_CTYPE, ""); // !!! FIXME: we assume you have a UTF-8 terminal. 74 | if (initscr() == NULL) { 75 | fprintf(stderr, "ncurses: initscr() failed\n"); 76 | return 0; 77 | } // if 78 | 79 | cbreak(); 80 | keypad(stdscr, TRUE); 81 | noecho(); 82 | start_color(); 83 | use_default_colors(); 84 | 85 | // map to VIO attributes... 86 | static const short curses_colormap[] = { 87 | COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, 88 | COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE 89 | }; 90 | 91 | if (COLORS >= 64) { // foreground and background 92 | for (uint32 i = 0; i < 8; i++) { 93 | for (uint32 j = 0; j < 8; j++) { 94 | const int pair = (int) (i | (j << 3)); 95 | init_pair(pair, curses_colormap[i], (j == 0) ? -1 : curses_colormap[j]); 96 | } // for 97 | } // for 98 | } else if (COLORS >= 8) { // just foregrounds 99 | for (int i = 0; i < 8; i++) 100 | init_pair(i, curses_colormap[i], COLOR_BLACK); 101 | } // else if 102 | 103 | // (otherwise, we won't set colors at all.) 104 | 105 | int scrh, scrw; 106 | getmaxyx(stdscr, scrh, scrw); 107 | 108 | const size_t buflen = scrw * scrh * sizeof (uint16); 109 | vio_buffer = malloc(buflen); 110 | if (!vio_buffer) { 111 | endwin(); 112 | delwin(stdscr); // not sure if this is safe, but valgrind said it leaks. 113 | stdscr = NULL; 114 | return 0; 115 | } // if 116 | 117 | memset(vio_buffer, '\0', buflen); 118 | vio_scrw = (uint16) scrw; 119 | vio_scrh = (uint16) scrh; 120 | vio_curx = vio_cury = 0; 121 | 122 | FIXME("these are just the default values OS/2 4.52 returns"); 123 | vio_cursorinfo.yStart = 15; 124 | vio_cursorinfo.cEnd = 15; 125 | vio_cursorinfo.cx = 1; 126 | vio_cursorinfo.attr = 0; 127 | 128 | return 1; 129 | } // initNcurses 130 | 131 | static void deinitNcurses(void) 132 | { 133 | if (!vio_buffer) 134 | return; 135 | 136 | // !!! FIXME: this is wrong 137 | //endwin(); 138 | reset_shell_mode(); 139 | 140 | printf("\n"); fflush(stdout); 141 | 142 | delwin(stdscr); // not sure if this is safe, but valgrind said it leaks. 143 | stdscr = NULL; 144 | free(vio_buffer); 145 | vio_buffer = NULL; 146 | vio_curx = vio_cury = vio_scrw = vio_scrh = 0; 147 | } // deinitNcurses 148 | 149 | static inline void commitToNcurses(void) 150 | { 151 | refresh(); 152 | } // commitToNcurses 153 | 154 | static void pushToNcurses(const int y, const int x, int numcells, const int commit) 155 | { 156 | const uint8 *src = (const uint8 *) (vio_buffer + ((y * vio_scrw) + x)); 157 | const uint32 avail = (((vio_scrh - y) * vio_scrw) - x); 158 | if (numcells > avail) 159 | numcells = avail; 160 | 161 | move(y, x); 162 | 163 | for (int i = 0; i < numcells; i++) { 164 | const uint8 viochar = *(src++); 165 | const uint8 vioattr = *(src++); 166 | 167 | chtype ch; 168 | switch (viochar) { 169 | case 0xC4: ch = ACS_HLINE; break; 170 | case 0xB3: ch = ACS_VLINE; break; 171 | case 0xDA: ch = ACS_ULCORNER; break; 172 | case 0xBF: ch = ACS_URCORNER; break; 173 | case 0xC0: ch = ACS_LLCORNER; break; 174 | case 0xD9: ch = ACS_LRCORNER; break; 175 | default: ch = (chtype) viochar; break; 176 | } // switch 177 | 178 | chtype attr = 0; 179 | 180 | if (COLORS >= 64) { // foreground and background 181 | const int color = ((vioattr & 0x70) >> 1) | (vioattr & 0x7); 182 | attr |= COLOR_PAIR(color); 183 | } else if (COLORS >= 8) { // just foregrounds 184 | const int color = (vioattr & 0x7); 185 | attr |= COLOR_PAIR(color); 186 | } // else if 187 | 188 | if (vioattr & VIOATTR_INTENSITY) 189 | attr |= A_BOLD; 190 | if (vioattr & VIOATTR_BLINK) 191 | attr |= A_BLINK; 192 | 193 | addch(ch | attr); 194 | } // for 195 | 196 | move(vio_cury, vio_curx); 197 | 198 | if (commit) 199 | commitToNcurses(); 200 | } // pushToNcurses 201 | 202 | APIRET16 VioGetMode(PVIOMODEINFO pvioModeInfo, HVIO hvio) 203 | { 204 | TRACE_NATIVE("VioGetMode(%p, %u)", pvioModeInfo, (uint) hvio); 205 | 206 | if (hvio != 0) 207 | return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented. 208 | else if (pvioModeInfo == NULL) 209 | return ERROR_VIO_INVALID_PARMS; 210 | else if (pvioModeInfo->cb != sizeof (*pvioModeInfo)) 211 | return ERROR_VIO_INVALID_LENGTH; 212 | 213 | //FIXME("might need to init ncurses at some point, but not yet."); 214 | else if (!initNcurses()) 215 | return ERROR_VIO_INVALID_HANDLE; 216 | 217 | memset(pvioModeInfo, '\0', sizeof (*pvioModeInfo)); 218 | pvioModeInfo->cb = sizeof (*pvioModeInfo); 219 | pvioModeInfo->fbType = VGMT_OTHER; 220 | pvioModeInfo->color = 4; 221 | pvioModeInfo->col = vio_scrw; 222 | pvioModeInfo->row = vio_scrh; 223 | pvioModeInfo->hres = 640; 224 | pvioModeInfo->vres = 400; 225 | pvioModeInfo->fmt_ID = 0; 226 | pvioModeInfo->attrib = 1; 227 | FIXME("fill in the rest of these"); 228 | //ULONG buf_addr; 229 | //ULONG buf_length; 230 | //ULONG full_length; 231 | //ULONG partial_length; 232 | //PCHAR ext_data_addr; 233 | 234 | return NO_ERROR; 235 | } // VioGetMode 236 | 237 | APIRET16 VioGetCurPos(PUSHORT pusRow, PUSHORT pusColumn, HVIO hvio) 238 | { 239 | TRACE_NATIVE("VioGetCurPos(%p, %p, %u)", pusRow, pusColumn, (uint) hvio); 240 | 241 | if (hvio != 0) 242 | return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented. 243 | else if (!initNcurses()) 244 | return ERROR_VIO_INVALID_HANDLE; 245 | 246 | if (pusRow) 247 | *pusRow = vio_cury; 248 | 249 | if (pusColumn) 250 | *pusColumn = vio_curx; 251 | 252 | return NO_ERROR; 253 | } // VioGetCurPos 254 | 255 | APIRET16 VioGetBuf(PULONG pLVB, PUSHORT pcbLVB, HVIO hvio) 256 | { 257 | TRACE_NATIVE("VioGetBuf(%p, %p, %u)", pLVB, pcbLVB, (uint) hvio); 258 | 259 | if (hvio != 0) 260 | return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented. 261 | else if (!initNcurses()) 262 | return ERROR_VIO_INVALID_HANDLE; 263 | if (pLVB) 264 | *pLVB = (ULONG) vio_buffer; 265 | if (pcbLVB) 266 | *pcbLVB = vio_scrw * vio_scrh * sizeof (ULONG); 267 | return NO_ERROR; 268 | } // VioGetBuf 269 | 270 | APIRET16 VioGetCurType(PVIOCURSORINFO pvioCursorInfo, HVIO hvio) 271 | { 272 | TRACE_NATIVE("VioGetCurType(%p, %u)", pvioCursorInfo, (uint) hvio); 273 | return NO_ERROR; 274 | 275 | if (hvio != 0) 276 | return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented. 277 | else if (pvioCursorInfo == NULL) 278 | return ERROR_VIO_INVALID_PARMS; 279 | else if (!initNcurses()) 280 | return ERROR_VIO_INVALID_HANDLE; 281 | 282 | memcpy(pvioCursorInfo, &vio_cursorinfo, sizeof (*pvioCursorInfo)); 283 | return NO_ERROR; 284 | } // VioGetCurType 285 | 286 | APIRET16 VioScrollUp(USHORT usTopRow, USHORT usLeftCol, USHORT usBotRow, USHORT usRightCol, USHORT cbLines, PBYTE pCell, HVIO hvio) 287 | { 288 | TRACE_NATIVE("VioScrollUp(%u, %u, %u, %u, %u, %p, %u)", (uint) usTopRow, (uint) usLeftCol, (uint) usBotRow, (uint) usRightCol, (uint) cbLines, pCell, (uint) hvio); 289 | FIXME("buggy"); 290 | return NO_ERROR; // !!! FIXME: buggy 291 | if (hvio != 0) 292 | return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented. 293 | else if (pCell == NULL) 294 | return ERROR_VIO_INVALID_PARMS; 295 | else if (!initNcurses()) 296 | return ERROR_VIO_INVALID_HANDLE; 297 | 298 | if (usLeftCol >= vio_scrw) 299 | usLeftCol = vio_scrw - 1; 300 | if (usRightCol >= vio_scrw) 301 | usRightCol = vio_scrw - 1; 302 | if (usTopRow >= vio_scrh) 303 | usTopRow = vio_scrh - 1; 304 | if (usBotRow >= vio_scrh) 305 | usBotRow = vio_scrh - 1; 306 | 307 | if (usLeftCol >= usRightCol) 308 | return NO_ERROR; // already done. 309 | else if (usTopRow >= usBotRow) 310 | return NO_ERROR; // already done. 311 | else if (cbLines == 0) 312 | return NO_ERROR; // already done. 313 | 314 | const uint32 rowlen = (usRightCol - usLeftCol) + 1; 315 | const uint32 overlines = (cbLines > usTopRow) ? (cbLines - usTopRow) : 0; 316 | const uint32 collen = ((usBotRow - usTopRow) + 1) - overlines; 317 | const uint32 adjust = overlines * vio_scrw; 318 | 319 | uint16 *src = vio_buffer + ((usTopRow * vio_scrw) + usLeftCol) + adjust; 320 | uint16 *dst = (src - (cbLines * vio_scrw)) + adjust; 321 | const size_t rowcpylen = rowlen * sizeof (uint16); 322 | for (uint32 i = 0; i < collen; i++) { 323 | memcpy(dst, src, rowcpylen); 324 | src += vio_scrw; 325 | dst += vio_scrw; 326 | } // for 327 | 328 | const uint16 clear_cell = *((uint16 *) pCell); 329 | for (uint32 i = 0; i < cbLines; i++) { 330 | if (dst >= (vio_buffer + (vio_scrw * vio_scrh))) 331 | break; // !!! FIXME: just calculate this outside the loop and adjust cbLines. 332 | uint16 *origdst = dst; 333 | for (uint32 j = 0; j < rowlen; j++) { 334 | *(dst++) = clear_cell; 335 | } 336 | dst = origdst + vio_scrw; 337 | } // for 338 | 339 | int starty = usTopRow - cbLines; 340 | if (starty < 0) 341 | starty = 0; 342 | int endy = starty + collen + cbLines; 343 | if (endy >= vio_scrh) 344 | endy = vio_scrh; 345 | 346 | for (int y = starty; y < endy; y++) 347 | pushToNcurses(y, usLeftCol, rowlen, 0); 348 | commitToNcurses(); 349 | 350 | return NO_ERROR; 351 | } // VioScrollUp 352 | 353 | APIRET16 VioSetCurPos(USHORT usRow, USHORT usColumn, HVIO hvio) 354 | { 355 | TRACE_NATIVE("VioSetCurPos(%u, %u, %u)", (uint) usRow, (uint) usColumn, (uint) hvio); 356 | if (hvio != 0) 357 | return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented. 358 | else if (!initNcurses()) 359 | return ERROR_VIO_INVALID_HANDLE; 360 | else if (usRow >= vio_scrh) 361 | return ERROR_VIO_ROW; 362 | else if (usColumn >= vio_scrw) 363 | return ERROR_VIO_COL; 364 | 365 | vio_cury = usRow; 366 | vio_curx = usColumn; 367 | 368 | move(vio_cury, vio_curx); 369 | refresh(); 370 | 371 | return NO_ERROR; 372 | } // VioSetCurPos 373 | 374 | APIRET16 VioSetCurType(PVIOCURSORINFO pvioCursorInfo, HVIO hvio) 375 | { 376 | TRACE_NATIVE("VioSetCurType(%p, %u)", pvioCursorInfo, (uint) hvio); 377 | FIXME("write me"); 378 | return NO_ERROR; 379 | } // VioSetCurType 380 | 381 | APIRET16 VioReadCellStr(PCH pchCellStr, PUSHORT pcb, USHORT usRow, USHORT usColumn, HVIO hvio) 382 | { 383 | TRACE_NATIVE("VioReadCellStr(%p, %p, %u, %u, %u)", pchCellStr, pcb, (uint) usRow, (uint) usColumn, (uint) hvio); 384 | 385 | if (hvio != 0) 386 | return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented. 387 | else if (!initNcurses()) 388 | return ERROR_VIO_INVALID_HANDLE; 389 | else if (usRow >= vio_scrh) 390 | return ERROR_VIO_ROW; 391 | else if (usColumn >= vio_scrw) 392 | return ERROR_VIO_COL; 393 | 394 | const uint32 maxidx = ((uint32)vio_scrh) * ((uint32)vio_scrw); 395 | const uint32 idx = (((uint32)usRow) * ((uint32)vio_scrw)) + ((uint32)usColumn); 396 | const uint32 avail = (maxidx - idx) * sizeof (uint16); 397 | if (((uint32) *pcb) > avail) 398 | *pcb = (USHORT) avail; 399 | memcpy(pchCellStr, vio_buffer + idx, (size_t) *pcb); 400 | return NO_ERROR; 401 | } // VioReadCellStr 402 | 403 | APIRET16 VioWrtCellStr(PCH pchCellStr, USHORT cb, USHORT usRow, USHORT usColumn, HVIO hvio) 404 | { 405 | TRACE_NATIVE("VioWrtCellStr(%p, %u, %u, %u, %u)", pchCellStr, (uint) cb, (uint) usRow, (uint) usColumn, (uint) hvio); 406 | 407 | if (hvio != 0) 408 | return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented. 409 | else if (!initNcurses()) 410 | return ERROR_VIO_INVALID_HANDLE; 411 | else if (usRow >= vio_scrh) 412 | return ERROR_VIO_ROW; 413 | else if (usColumn >= vio_scrw) 414 | return ERROR_VIO_COL; 415 | 416 | const uint16 *src = (uint16 *) pchCellStr; 417 | uint16 *dst = vio_buffer + ((usRow * vio_scrw) + usColumn); 418 | const uint32 avail = (((vio_scrh - usRow) * vio_scrw) - usColumn) * sizeof (uint16); 419 | if (((uint32) cb) > avail) 420 | cb = (USHORT) avail; 421 | 422 | memcpy(dst, src, cb); // !!! FIXME: what happens if cb extends into half a cell? 423 | 424 | pushToNcurses(usRow, usColumn, cb / sizeof (uint16), 1); 425 | 426 | return NO_ERROR; 427 | } // VioWrtCellStr 428 | 429 | APIRET16 VioWrtCharStrAtt(PCH pch, USHORT cb, USHORT usRow, USHORT usColumn, PBYTE pAttr, HVIO hvio) 430 | { 431 | TRACE_NATIVE("VioWrtCharStrAtt(%p, %u, %u, %u, %p, %u)", pch, (uint) cb, (uint) usRow, (uint) usColumn, pAttr, (uint) hvio); 432 | 433 | if (hvio != 0) 434 | return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented. 435 | else if (!initNcurses()) 436 | return ERROR_VIO_INVALID_HANDLE; 437 | else if (usRow >= vio_scrh) 438 | return ERROR_VIO_ROW; 439 | else if (usColumn >= vio_scrw) 440 | return ERROR_VIO_COL; 441 | 442 | const uint8 attr = *pAttr; 443 | const uint8 *src = (uint8 *) pch; 444 | uint8 *dst = (uint8 *) (vio_buffer + ((usRow * vio_scrw) + usColumn)); 445 | const uint32 avail = (((vio_scrh - usRow) * vio_scrw) - usColumn); 446 | if (((uint32) cb) > avail) 447 | cb = (USHORT) avail; 448 | 449 | for (uint32 i = 0; i < cb; i++, src++) { 450 | *(dst++) = *src; 451 | *(dst++) = attr; 452 | } // for 453 | 454 | pushToNcurses(usRow, usColumn, cb, 1); 455 | 456 | return NO_ERROR; 457 | } // VioWrtCharStrAtt 458 | 459 | APIRET16 VioWrtNCell(PBYTE pCell, USHORT cb, USHORT usRow, USHORT usColumn, HVIO hvio) 460 | { 461 | TRACE_NATIVE("VioWrtNCell(%p, %u, %u, %u, %u)", pCell, (uint) cb, (uint) usRow, (uint) usColumn, (uint) hvio); 462 | 463 | if (hvio != 0) 464 | return ERROR_VIO_INVALID_HANDLE; // !!! FIXME: can be non-zero when VioCreatePS() is implemented. 465 | else if (!initNcurses()) 466 | return ERROR_VIO_INVALID_HANDLE; 467 | else if (usRow >= vio_scrh) 468 | return ERROR_VIO_ROW; 469 | else if (usColumn >= vio_scrw) 470 | return ERROR_VIO_COL; 471 | 472 | const uint16 cell = *((uint16 *) pCell); 473 | uint16 *dst = vio_buffer + ((usRow * vio_scrw) + usColumn); 474 | const uint32 avail = (((vio_scrh - usRow) * vio_scrw) - usColumn); 475 | if (((uint32) cb) > avail) 476 | cb = (USHORT) avail; 477 | 478 | for (uint32 i = 0; i < cb; i++) 479 | *(dst++) = cell; 480 | 481 | pushToNcurses(usRow, usColumn, cb, 1); 482 | 483 | return NO_ERROR; 484 | } // VioWrtNCell 485 | 486 | LX_NATIVE_DESTRUCTOR(viocalls) 487 | { 488 | deinitNcurses(); 489 | } 490 | 491 | // end of viocalls.c ... 492 | 493 | -------------------------------------------------------------------------------- /native/viocalls.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 2ine; an OS/2 emulator for Linux. 3 | * 4 | * Please see the file LICENSE.txt in the source's root directory. 5 | * 6 | * This file written by Ryan C. Gordon. 7 | */ 8 | 9 | #ifndef _INCL_VIOCALLS_H_ 10 | #define _INCL_VIOCALLS_H_ 11 | 12 | #include "os2types.h" 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | #pragma pack(push, 1) 19 | typedef struct 20 | { 21 | USHORT cb; 22 | UCHAR fbType; 23 | UCHAR color; 24 | USHORT col; 25 | USHORT row; 26 | USHORT hres; 27 | USHORT vres; 28 | UCHAR fmt_ID; 29 | UCHAR attrib; 30 | ULONG buf_addr; 31 | ULONG buf_length; 32 | ULONG full_length; 33 | ULONG partial_length; 34 | PCHAR ext_data_addr; 35 | } VIOMODEINFO, *PVIOMODEINFO; 36 | #pragma pack(pop) 37 | 38 | enum 39 | { 40 | VGMT_OTHER = 0x1, 41 | VGMT_GRAPHICS = 0x02, 42 | VGMT_DISABLEBURST = 0x04 43 | }; 44 | 45 | typedef struct 46 | { 47 | USHORT yStart; 48 | USHORT cEnd; 49 | USHORT cx; 50 | USHORT attr; 51 | } VIOCURSORINFO, *PVIOCURSORINFO; 52 | 53 | OS2EXPORT APIRET16 OS2API16 VioGetMode(PVIOMODEINFO pvioModeInfo, HVIO hvio) OS2APIINFO(ord=21,name=VIOGETMODE); 54 | OS2EXPORT APIRET16 OS2API16 VioGetCurPos(PUSHORT pusRow, PUSHORT pusColumn, HVIO hvio) OS2APIINFO(ord=9,name=VIOGETCURPOS); 55 | OS2EXPORT APIRET16 OS2API16 VioGetBuf(PULONG pLVB, PUSHORT pcbLVB, HVIO hvio) OS2APIINFO(ord=31,name=VIOGETBUF); 56 | OS2EXPORT APIRET16 OS2API16 VioGetCurType(PVIOCURSORINFO pvioCursorInfo, HVIO hvio) OS2APIINFO(ord=27,name=VIOGETCURTYPE); 57 | OS2EXPORT APIRET16 OS2API16 VioScrollUp(USHORT usTopRow, USHORT usLeftCol, USHORT usBotRow, USHORT usRightCol, USHORT cbLines, PBYTE pCell, HVIO hvio) OS2APIINFO(ord=7,name=VIOSCROLLUP); 58 | OS2EXPORT APIRET16 OS2API16 VioSetCurPos(USHORT usRow, USHORT usColumn, HVIO hvio) OS2APIINFO(ord=15,name=VIOSETCURPOS); 59 | OS2EXPORT APIRET16 OS2API16 VioSetCurType(PVIOCURSORINFO pvioCursorInfo, HVIO hvio) OS2APIINFO(ord=32,name=VIOSETCURTYPE); 60 | OS2EXPORT APIRET16 OS2API16 VioReadCellStr(PCH pchCellStr, PUSHORT pcb, USHORT usRow, USHORT usColumn, HVIO hvio) OS2APIINFO(ord=24,name=VIOREADCELLSTR); 61 | OS2EXPORT APIRET16 OS2API16 VioWrtCellStr(PCH pchCellStr, USHORT cb, USHORT usRow, USHORT usColumn, HVIO hvio) OS2APIINFO(ord=10,name=VIOWRTCELLSTR); 62 | OS2EXPORT APIRET16 OS2API16 VioWrtCharStrAtt(PCH pch, USHORT cb, USHORT usRow, USHORT usColumn, PBYTE pAttr, HVIO hvio) OS2APIINFO(ord=48,name=VIOWRTCHARSTRATT); 63 | OS2EXPORT APIRET16 OS2API16 VioWrtNCell(PBYTE pCell, USHORT cb, USHORT usRow, USHORT usColumn, HVIO hvio) OS2APIINFO(ord=52,name=VIOWRTNCELL); 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | 69 | #endif 70 | 71 | // end of viocalls.h ... 72 | 73 | -------------------------------------------------------------------------------- /research/1996-10-09_Rel_10_IBM_OS2_16-32-BIT_OBJECT_MODULE_FORMAT_(OMF)_AND_LINEAR_EXECUTABLE_MODULE_FORMAT_(LX)-lx386.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icculus/2ine/1ca194f39b6322d5c6cc1006616ed6a62f74c193/research/1996-10-09_Rel_10_IBM_OS2_16-32-BIT_OBJECT_MODULE_FORMAT_(OMF)_AND_LINEAR_EXECUTABLE_MODULE_FORMAT_(LX)-lx386.pdf -------------------------------------------------------------------------------- /research/The Effect of Compression on Performance in a Demand Paging System.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icculus/2ine/1ca194f39b6322d5c6cc1006616ed6a62f74c193/research/The Effect of Compression on Performance in a Demand Paging System.pdf -------------------------------------------------------------------------------- /research/ldt.c: -------------------------------------------------------------------------------- 1 | // "man modify_ldt" 2 | 3 | #define _GNU_SOURCE 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main(void) 13 | { 14 | struct user_desc ldt[8 * 1024]; 15 | long rc; 16 | 17 | //rc = syscall(123, (int) 0, (void *) ldt, (unsigned long) sizeof (ldt)); 18 | //printf("read syscall == %ld\n", rc); 19 | 20 | char *str = malloc(64); 21 | strcpy(str, "hello world!"); 22 | printf("&str == %p\n", str); 23 | 24 | unsigned int fs = 0xFFFFFFFF; 25 | __asm__ __volatile__ ( 26 | "xorl %%eax, %%eax \n\t" 27 | "movw %%fs, %%ax \n\t" 28 | : "=a" (fs) 29 | ); 30 | 31 | printf("Current %%fs: 0x%X\n", fs); 32 | 33 | struct user_desc *entry = ldt; 34 | entry->entry_number = -1; 35 | entry->base_addr = (unsigned long) str; 36 | entry->limit = 64; 37 | entry->seg_32bit = 1; 38 | entry->contents = MODIFY_LDT_CONTENTS_DATA; 39 | entry->read_exec_only = 0; 40 | entry->limit_in_pages = 0; 41 | entry->seg_not_present = 0; 42 | entry->useable = 1; 43 | 44 | printf("entry=%u, base=%p, limit=%u\n", entry->entry_number, (void *) entry->base_addr, entry->limit); 45 | 46 | // modify_ldt 47 | // rc = syscall(SYS_modify_ldt, (int) 1, (void *) entry, (unsigned long) sizeof (*entry)); 48 | // printf("write syscall == %ld\n", rc); 49 | 50 | // set_thread_area 51 | rc = syscall(SYS_set_thread_area, entry); 52 | printf("write syscall == %ld\n", rc); 53 | 54 | printf("entry==%d\n", (int) (entry->entry_number)); 55 | 56 | // this doesn't give you a user_desc struct back, I think it gives you the real LDT entry...? 57 | // rc = syscall(SYS_modify_ldt, (int) 0, (void *) entry, (unsigned long) sizeof (*entry) * 128); 58 | // printf("read syscall == %ld\n", rc); 59 | 60 | // long i; 61 | // for (i = 0; i < 128; i++, entry++) 62 | // printf("entry=%u, base=%p, limit=%u\n", entry->entry_number, (void *) entry->base_addr, entry->limit); 63 | 64 | // I have no idea why this needs the "<< 3 | 3", but it's probably 65 | // specified in the Intel manuals. I got this from looking at how 66 | // Wine does it. 67 | __asm__ __volatile__ ( 68 | //"pushw %%ax\n\t" 69 | //"popw %%fs \n\t" 70 | "movw %%ax,%%fs \n\t" 71 | : 72 | : "a" ((entry->entry_number << 3) | 3) 73 | ); 74 | 75 | fs = 0xFFFFFFFF; 76 | __asm__ __volatile__ ( 77 | "xorl %%eax, %%eax \n\t" 78 | "movw %%fs, %%ax \n\t" 79 | : "=a" (fs) 80 | ); 81 | 82 | printf("New %%fs: 0x%X\n", fs); 83 | 84 | char newstr[16]; 85 | memset(newstr, '\0', sizeof (newstr)); 86 | __asm__ __volatile__ ( 87 | "movl %%fs:0,%%eax\n\t" 88 | "movl %%eax,(%%edi)\n\t" 89 | "movl %%fs:4,%%eax\n\t" 90 | "movl %%eax,4(%%edi)\n\t" 91 | "movl %%fs:8,%%eax\n\t" 92 | "movl %%eax,8(%%edi)\n\t" 93 | : 94 | : "D" (newstr) 95 | : "eax" 96 | ); 97 | 98 | printf("copied string == '%s'\n", newstr); 99 | 100 | return 0; 101 | } 102 | 103 | // end of ldt.c ... 104 | 105 | -------------------------------------------------------------------------------- /research/neexe.txt: -------------------------------------------------------------------------------- 1 | (found this text file at http://benoit.papillault.free.fr/c/disc2/exefmt.txt --ryan.) 2 | 3 | 4 | INF: Executable-File Header Format [P_WinSDK] 5 | 6 | 3.00 7 | WINDOWS 8 | PSSONLY | Windows 3 Developers Notes softlib ENDUSER 9 | 10 | Summary: 11 | 12 | Note: This article is part of a set of seven articles, collectively 13 | called the "Windows 3.00 Developer's Notes." More information about 14 | the contents of the other articles, and procedures for ordering a 15 | hard-copy set, can be found in the knowledge base article titled "INF: 16 | The Windows 3.00 Developer's Notes" (Q65260). 17 | 18 | This article can be found in the Software/Data Library by searching on 19 | the word EXEFMT or S12688. EXEFMT was archived using the PKware 20 | file-compression utility. 21 | 22 | More Information: 23 | 24 | Microsoft defined the segmented executable file format for Windows 25 | applications and dynamic-link libraries (DLLs). This file format is 26 | also referred to as the New Executable Format. This new format is an 27 | extension of the existing MS-DOS .EXE format (old-style format). The 28 | purpose of the segmented executable format is to provide the 29 | information needed to support the dynamic linking and segmentation 30 | capabilities of the Windows environment. 31 | 32 | An executable file contains Microsoft Windows code and data, or 33 | Windows code, data, and resources. Specific fields have been added to 34 | the old-style .EXE format header to indicate the existence of the 35 | segmented file format. The old-style header may contain a valid 36 | executable program, called a stub program, that will be executed if 37 | the program is run on MS-DOS (without Windows). This stub program 38 | usually prints a message indicating that Microsoft Windows is required 39 | to run the program. The segmented executable format extensions also 40 | begin with a header that describes the contents and location of the 41 | executable image in the file. The loader uses this header information 42 | when it loads the executable segments in memory. 43 | 44 | 45 | ====================================================================== 46 | OLD-STYLE HEADER EXTENSIONS 47 | ====================================================================== 48 | 49 | The old-style header contains information the loader expects for a DOS 50 | executable file. It describes a stub program (WINSTUB) the loader can 51 | place in memory when necessary, it points to the new-style header, and 52 | it contains the stub programs relocation table. 53 | 54 | The following illustrates the distinct parts of the old-style 55 | executable format: 56 | 57 | +-------------------------+ 58 | 00h | Old-style header info | 59 | +-------------------------+ 60 | 20h | Reserved | 61 | +-------------------------+ 62 | 3Ch | Offset to segmented | 63 | | .EXE header | 64 | +-------------------------+ 65 | 40h | Relocation table and | 66 | | DOS stub program | 67 | +-------------------------+ 68 | | Segmented .EXE Header | 69 | | . | 70 | | . | 71 | | . | 72 | 73 | The word at offset 18h in the old-style .EXE header contains the 74 | relative byte offset to the stub program's relocation table. If this 75 | offset is 40h, then the double word at offset 3Ch is assumed to be the 76 | relative byte offset from the beginning of the file to the beginning 77 | of the segmented executable header. A new-format .EXE file is 78 | identified if the segmented executable header contains a valid 79 | signature. If the signature is not valid, the file is assumed to be an 80 | old-style format .EXE file. The remainder of the old-style format 81 | header will describe a DOS program, the stub. The stub may be any 82 | valid program but will typically be a program that displays an error 83 | message. 84 | 85 | ====================================================================== 86 | SEGMENTED EXE FORMAT 87 | ====================================================================== 88 | 89 | Because Windows executable files are often larger than one segment 90 | (64K), additional information (that does not appear in the old-style 91 | header) is required so that the loader can load each segment properly. 92 | The segmented EXE format was developed to provide the loader with this 93 | information. 94 | 95 | The segmented .EXE file has the following format: 96 | 97 | +-----------------+ 98 | 00h | Old-style EXE | 99 | | Header | 100 | +-----------------+ 101 | 20h | Reserved | 102 | +-----------------+ 103 | 3Ch | Offset to | ---+ 104 | | Segmented Header| | 105 | +-----------------+ | 106 | 40h | Relocation Table| | 107 | | & Stub Program | | 108 | +-----------------+ | 109 | | | | 110 | +-----------------+ | 111 | xxh | Segmented EXE | <--+ 112 | | Header | 113 | +-----------------+ 114 | | Segment Table | 115 | +-----------------+ 116 | | Resource Table | 117 | +-----------------+ 118 | | Resident Name | 119 | | Table | 120 | +-----------------+ 121 | | Module Reference| 122 | | Table | 123 | +-----------------+ 124 | | Imported Names | 125 | | Table | 126 | +-----------------+ 127 | | Entry Table | 128 | +-----------------+ 129 | | Non-Resident | 130 | | Name Table | 131 | +-----------------+ 132 | | Seg #1 Data | 133 | | Seg #1 Info | 134 | +-----------------+ 135 | . 136 | . 137 | . 138 | +-----------------+ 139 | | Seg #n Data | 140 | | Seg #n Info | 141 | +-----------------+ 142 | 143 | 144 | The following sections describe each of the components that make up 145 | the segmented EXE format. Each section contains a description of the 146 | component and the fields in the structures that make up that 147 | component. 148 | 149 | Note: All unused fields and flag bits are reserved for future use and 150 | must contain 0 (zero) values. 151 | 152 | ====================================================================== 153 | SEGMENTED EXE HEADER 154 | ====================================================================== 155 | 156 | The segmented EXE header contains general information about the EXE 157 | file and contains information on the location and size of the other 158 | sections. The Windows loader copies this section, along with other 159 | data, into the module table in the system data. The module table is 160 | internal data used by the loader to manage the loaded executable 161 | modules in the system and to support dynamic linking. 162 | 163 | The following describes the format of the segmented executable header. 164 | For each field, the offset is given relative to the beginning of the 165 | segmented header, the size of the field is defined, and a description 166 | is given. 167 | 168 | Offset Size Description 169 | ------ ---- ----------- 170 | 171 | 00h DW Signature word. 172 | "N" is low-order byte. 173 | "E" is high-order byte. 174 | 175 | 02h DB Version number of the linker. 176 | 177 | 03h DB Revision number of the linker. 178 | 179 | 04h DW Entry Table file offset, relative to the beginning of 180 | the segmented EXE header. 181 | 06h DW Number of bytes in the entry table. 182 | 183 | 08h DD 32-bit CRC of entire contents of file. 184 | These words are taken as 00 during the calculation. 185 | 186 | 0Ch DW Flag word. 187 | 0000h = NOAUTODATA 188 | 0001h = SINGLEDATA (Shared automatic data segment) 189 | 0002h = MULTIPLEDATA (Instanced automatic data 190 | segment) 191 | 2000h = Errors detected at link time, module will not 192 | load. 193 | 8000h = Library module. 194 | The SS:SP information is invalid, CS:IP points 195 | to an initialization procedure that is called 196 | with AX equal to the module handle. This 197 | initialization procedure must perform a far 198 | return to the caller, with AX not equal to 199 | zero to indicate success, or AX equal to zero 200 | to indicate failure to initialize. DS is set 201 | to the library's data segment if the 202 | SINGLEDATA flag is set. Otherwise, DS is set 203 | to the caller's data segment. 204 | 205 | A program or DLL can only contain dynamic 206 | links to executable files that have this 207 | library module flag set. One program cannot 208 | dynamic-link to another program. 209 | 210 | 0Eh DW Segment number of automatic data segment. 211 | This value is set to zero if SINGLEDATA and 212 | MULTIPLEDATA flag bits are clear, NOAUTODATA is 213 | indicated in the flags word. 214 | 215 | A Segment number is an index into the module's segment 216 | table. The first entry in the segment table is segment 217 | number 1. 218 | 219 | 10h DW Initial size, in bytes, of dynamic heap added to the 220 | data segment. This value is zero if no initial local 221 | heap is allocated. 222 | 223 | 12h DW Initial size, in bytes, of stack added to the data 224 | segment. This value is zero to indicate no initial 225 | stack allocation, or when SS is not equal to DS. 226 | 227 | 14h DD Segment number:offset of CS:IP. 228 | 229 | 18h DD Segment number:offset of SS:SP. 230 | If SS equals the automatic data segment and SP equals 231 | zero, the stack pointer is set to the top of the 232 | automatic data segment just below the additional heap 233 | area. 234 | 235 | +--------------------------+ 236 | | additional dynamic heap | 237 | +--------------------------+ <- SP 238 | | additional stack | 239 | +--------------------------+ 240 | | loaded auto data segment | 241 | +--------------------------+ <- DS, SS 242 | 243 | 1Ch DW Number of entries in the Segment Table. 244 | 245 | 1Eh DW Number of entries in the Module Reference Table. 246 | 20h DW Number of bytes in the Non-Resident Name Table. 247 | 248 | 22h DW Segment Table file offset, relative to the beginning 249 | of the segmented EXE header. 250 | 251 | 24h DW Resource Table file offset, relative to the beginning 252 | of the segmented EXE header. 253 | 254 | 26h DW Resident Name Table file offset, relative to the 255 | beginning of the segmented EXE header. 256 | 257 | 28h DW Module Reference Table file offset, relative to the 258 | beginning of the segmented EXE header. 259 | 260 | 2Ah DW Imported Names Table file offset, relative to the 261 | beginning of the segmented EXE header. 262 | 263 | 2Ch DD Non-Resident Name Table offset, relative to the 264 | beginning of the file. 265 | 266 | 30h DW Number of movable entries in the Entry Table. 267 | 268 | 32h DW Logical sector alignment shift count, log(base 2) of 269 | the segment sector size (default 9). 270 | 271 | 34h DW Number of resource entries. 272 | 273 | 36h DB Executable type, used by loader. 274 | 02h = WINDOWS 275 | 276 | 37h-3Fh DB Reserved, currently 0's. 277 | 278 | 279 | ====================================================================== 280 | SEGMENT TABLE 281 | ====================================================================== 282 | 283 | The segment table contains an entry for each segment in the executable 284 | file. The number of segment table entries are defined in the segmented 285 | EXE header. The first entry in the segment table is segment number 1. 286 | The following is the structure of a segment table entry. 287 | 288 | Size Description 289 | ---- ----------- 290 | 291 | DW Logical-sector offset (n byte) to the contents of the segment 292 | data, relative to the beginning of the file. Zero means no 293 | file data. 294 | 295 | DW Length of the segment in the file, in bytes. Zero means 64K. 296 | 297 | DW Flag word. 298 | 0007h = TYPE_MASK Segment-type field. 299 | 0000h = CODE Code-segment type. 300 | 0001h = DATA Data-segment type. 301 | 0010h = MOVEABLE Segment is not fixed. 302 | 0040h = PRELOAD Segment will be preloaded; read-only if 303 | this is a data segment. 304 | 0100h = RELOCINFO Set if segment has relocation records. 305 | F000h = DISCARD Discard priority. 306 | 307 | DW Minimum allocation size of the segment, in bytes. Total size 308 | of the segment. Zero means 64K. 309 | 310 | 311 | ====================================================================== 312 | RESOURCE TABLE 313 | ====================================================================== 314 | 315 | The resource table follows the segment table and contains entries for 316 | each resource in the executable file. The resource table consists of 317 | an alignment shift count, followed by a table of resource records. The 318 | resource records define the type ID for a set of resources. Each 319 | resource record contains a table of resource entries of the defined 320 | type. The resource entry defines the resource ID or name ID for the 321 | resource. It also defines the location and size of the resource. The 322 | following describes the contents of each of these structures: 323 | 324 | Size Description 325 | ---- ----------- 326 | 327 | DW Alignment shift count for resource data. 328 | 329 | A table of resource type information blocks follows. The following 330 | is the format of each type information block: 331 | 332 | DW Type ID. This is an integer type if the high-order bit is 333 | set (8000h); otherwise, it is an offset to the type string, 334 | the offset is relative to the beginning of the resource 335 | table. A zero type ID marks the end of the resource type 336 | information blocks. 337 | 338 | DW Number of resources for this type. 339 | 340 | DD Reserved. 341 | 342 | A table of resources for this type follows. The following is 343 | the format of each resource (8 bytes each): 344 | 345 | DW File offset to the contents of the resource data, 346 | relative to beginning of file. The offset is in terms 347 | of the alignment shift count value specified at 348 | beginning of the resource table. 349 | 350 | DW Length of the resource in the file (in bytes). 351 | 352 | DW Flag word. 353 | 0010h = MOVEABLE Resource is not fixed. 354 | 0020h = PURE Resource can be shared. 355 | 0040h = PRELOAD Resource is preloaded. 356 | 357 | DW Resource ID. This is an integer type if the high-order 358 | bit is set (8000h), otherwise it is the offset to the 359 | resource string, the offset is relative to the 360 | beginning of the resource table. 361 | 362 | DD Reserved. 363 | 364 | Resource type and name strings are stored at the end of the 365 | resource table. Note that these strings are NOT null terminated and 366 | are case sensitive. 367 | 368 | DB Length of the type or name string that follows. A zero value 369 | indicates the end of the resource type and name string, also 370 | the end of the resource table. 371 | 372 | DB ASCII text of the type or name string. 373 | 374 | 375 | ====================================================================== 376 | RESIDENT-NAME TABLE 377 | ====================================================================== 378 | 379 | The resident-name table follows the resource table, and contains this 380 | module's name string and resident exported procedure name strings. The 381 | first string in this table is this module's name. These name strings 382 | are case-sensitive and are not null-terminated. The following 383 | describes the format of the name strings: 384 | 385 | Size Description 386 | ---- ----------- 387 | 388 | DB Length of the name string that follows. A zero value indicates 389 | the end of the name table. 390 | 391 | DB ASCII text of the name string. 392 | 393 | DW Ordinal number (index into entry table). This value is ignored 394 | for the module name. 395 | 396 | 397 | ====================================================================== 398 | MODULE-REFERENCE TABLE 399 | ====================================================================== 400 | 401 | The module-reference table follows the resident-name table. Each entry 402 | contains an offset for the module-name string within the imported- 403 | names table; each entry is 2 bytes long. 404 | 405 | Size Description 406 | ---- ----------- 407 | 408 | DW Offset within Imported Names Table to referenced module name 409 | string. 410 | 411 | 412 | ====================================================================== 413 | IMPORTED-NAME TABLE 414 | ====================================================================== 415 | 416 | The imported-name table follows the module-reference table. This table 417 | contains the names of modules and procedures that are imported by the 418 | executable file. Each entry is composed of a 1-byte field that 419 | contains the length of the string, followed by any number of 420 | characters. The strings are not null-terminated and are case 421 | sensitive. 422 | 423 | Size Description 424 | ---- ----------- 425 | 426 | DB Length of the name string that follows. 427 | 428 | DB ASCII text of the name string. 429 | 430 | 431 | ====================================================================== 432 | ENTRY TABLE 433 | ====================================================================== 434 | 435 | The entry table follows the imported-name table. This table contains 436 | bundles of entry-point definitions. Bundling is done to save space in 437 | the entry table. The entry table is accessed by an ordinal value. 438 | Ordinal number one is defined to index the first entry in the entry 439 | table. To find an entry point, the bundles are scanned searching for a 440 | specific entry point using an ordinal number. The ordinal number is 441 | adjusted as each bundle is checked. When the bundle that contains the 442 | entry point is found, the ordinal number is multiplied by the size of 443 | the bundle's entries to index the proper entry. 444 | 445 | The linker forms bundles in the most dense manner it can, under the 446 | restriction that it cannot reorder entry points to improve bundling. 447 | The reason for this restriction is that other .EXE files may refer to 448 | entry points within this bundle by their ordinal number. The following 449 | describes the format of the entry table bundles. 450 | 451 | Size Description 452 | ---- ----------- 453 | 454 | DB Number of entries in this bundle. All records in one bundle 455 | are either moveable or refer to the same fixed segment. A zero 456 | value in this field indicates the end of the entry table. 457 | 458 | DB Segment indicator for this bundle. This defines the type of 459 | entry table entry data within the bundle. There are three 460 | types of entries that are defined. 461 | 462 | 000h = Unused entries. There is no entry data in an unused 463 | bundle. The next bundle follows this field. This is 464 | used by the linker to skip ordinal numbers. 465 | 466 | 001h-0FEh = Segment number for fixed segment entries. A fixed 467 | segment entry is 3 bytes long and has the following 468 | format. 469 | 470 | DB Flag word. 471 | 01h = Set if the entry is exported. 472 | 02h = Set if the entry uses a global (shared) data 473 | segments. 474 | The first assembly-language instruction in the 475 | entry point prologue must be "MOV AX,data 476 | segment number". This may be set only for 477 | SINGLEDATA library modules. 478 | 479 | DW Offset within segment to entry point. 480 | 481 | 0FFH = Moveable segment entries. The entry data contains the 482 | segment number for the entry points. A moveable segment 483 | entry is 6 bytes long and has the following format. 484 | 485 | DB Flag word. 486 | 01h = Set if the entry is exported. 487 | 02h = Set if the entry uses a global (shared) data 488 | segments. 489 | 490 | INT 3FH. 491 | 492 | DB Segment number. 493 | 494 | DW Offset within segment to entry point. 495 | 496 | 497 | ====================================================================== 498 | NONRESIDENT-NAME TABLE 499 | ====================================================================== 500 | 501 | The nonresident-name table follows the entry table, and contains a 502 | module description and nonresident exported procedure name strings. 503 | The first string in this table is a module description. These name 504 | strings are case-sensitive and are not null-terminated. The name 505 | strings follow the same format as those defined in the resident name 506 | table. 507 | 508 | 509 | ====================================================================== 510 | PER SEGMENT DATA 511 | ====================================================================== 512 | 513 | The location and size of the per-segment data is defined in the 514 | segment table entry for the segment. If the segment has relocation 515 | fixups, as defined in the segment table entry flags, they directly 516 | follow the segment data in the file. The relocation fixup information 517 | is defined as follows: 518 | 519 | 520 | Size Description 521 | ---- ----------- 522 | 523 | DW Number of relocation records that follow. 524 | 525 | A table of relocation records follows. The following is the format 526 | of each relocation record. 527 | 528 | DB Source type. 529 | 0Fh = SOURCE_MASK 530 | 00h = LOBYTE 531 | 02h = SEGMENT 532 | 03h = FAR_ADDR (32-bit pointer) 533 | 05h = OFFSET (16-bit offset) 534 | 535 | DB Flags byte. 536 | 03h = TARGET_MASK 537 | 00h = INTERNALREF 538 | 01h = IMPORTORDINAL 539 | 02h = IMPORTNAME 540 | 03h = OSFIXUP 541 | 04h = ADDITIVE 542 | 543 | DW Offset within this segment of the source chain. 544 | If the ADDITIVE flag is set, then target value is added to 545 | the source contents, instead of replacing the source and 546 | following the chain. The source chain is an 0FFFFh 547 | terminated linked list within this segment of all 548 | references to the target. 549 | 550 | The target value has four types that are defined in the flag 551 | byte field. The following are the formats for each target 552 | type: 553 | 554 | INTERNALREF 555 | 556 | DB Segment number for a fixed segment, or 0FFh for a 557 | movable segment. 558 | 559 | DB 0 560 | 561 | DW Offset into segment if fixed segment, or ordinal 562 | number index into Entry Table if movable segment. 563 | 564 | IMPORTNAME 565 | 566 | DW Index into module reference table for the imported 567 | module. 568 | 569 | DW Offset within Imported Names Table to procedure name 570 | string. 571 | 572 | IMPORTORDINAL 573 | 574 | DW Index into module reference table for the imported 575 | module. 576 | DW Procedure ordinal number. 577 | 578 | OSFIXUP 579 | 580 | DW Operating system fixup type. 581 | Floating-point fixups. 582 | 0001h = FIARQQ, FJARQQ 583 | 0002h = FISRQQ, FJSRQQ 584 | 0003h = FICRQQ, FJCRQQ 585 | 0004h = FIERQQ 586 | 0005h = FIDRQQ 587 | 0006h = FIWRQQ 588 | 589 | DW 0 590 | 591 | ====================================================================== 592 | 593 | Microsoft is a registered trademark and Windows is a trademark of 594 | Microsoft Corporation. 595 | 596 | Additional reference words: 3.0 597 | -------------------------------------------------------------------------------- /tests/emx.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icculus/2ine/1ca194f39b6322d5c6cc1006616ed6a62f74c193/tests/emx.dll -------------------------------------------------------------------------------- /tests/hello.asm: -------------------------------------------------------------------------------- 1 | ; This code is roughly from an example at: 2 | ; http://www.os2world.com/wiki/index.php/OS/2_Miniaturization_Contest 3 | ; 4 | ; Assembled/linked with OpenWatcom: 5 | ; 6 | ; wasm hello.asm 7 | ; wlink file hello lib os2386 option st=32k 8 | ; 9 | ; --ryan. 10 | 11 | .386p 12 | 13 | EXTRN DosPutMessage:BYTE 14 | 15 | _DATA SEGMENT BYTE PUBLIC USE32 'STACK' 16 | _msg: 17 | DB "Hello world! I'm a 32-bit OS/2 binary!", 0aH 18 | _DATA ENDS 19 | 20 | _TEXT SEGMENT BYTE PUBLIC USE32 'CODE' 21 | ASSUME CS:_TEXT, DS:_TEXT, SS:_TEXT 22 | 23 | startup: 24 | push offset flat:_msg 25 | push 40 26 | push 1 27 | call near ptr flat:DosPutMessage 28 | add esp,0CH 29 | ret 30 | _TEXT ENDS 31 | 32 | END startup 33 | 34 | -------------------------------------------------------------------------------- /tests/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main(void) { 3 | printf("hello world\n"); 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /tests/hello.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icculus/2ine/1ca194f39b6322d5c6cc1006616ed6a62f74c193/tests/hello.exe -------------------------------------------------------------------------------- /tests/hello16.c: -------------------------------------------------------------------------------- 1 | // wcc test16.c -bt=os2 -fo=.obj -zq -od -ms -i="C:\WATCOM\h\os21x" 2 | // wlink name test16 sys os2 op q file test16.obj 3 | 4 | #define INCL_DOS 5 | #include 6 | 7 | int main(void) 8 | { 9 | DosPutMessage(1, 32, "Hello from a 16-bit OS/2 .exe!\r\n"); 10 | return 0; 11 | } 12 | 13 | // end of hello16.c ... 14 | 15 | -------------------------------------------------------------------------------- /tests/hello16.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icculus/2ine/1ca194f39b6322d5c6cc1006616ed6a62f74c193/tests/hello16.exe -------------------------------------------------------------------------------- /tests/helloc.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icculus/2ine/1ca194f39b6322d5c6cc1006616ed6a62f74c193/tests/helloc.exe -------------------------------------------------------------------------------- /tests/testargv.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern char **environ; 4 | 5 | int main(int argc, char **argv) { 6 | int i; 7 | char **envp = environ; 8 | 9 | printf("Command line: (argc == %d)\n", argc); 10 | for (i = 0; i <= argc; i++) { 11 | printf("argv[%d] = '%s'\n", i, argv[i] ? argv[i] : "(null)"); 12 | } // for 13 | 14 | printf("\nEnvironment:\n"); 15 | for (i = 0; envp[i]; i++) { 16 | printf("envp[%d] = '%s'\n", i, envp[i] ? envp[i] : "(null)"); 17 | } // for 18 | 19 | return 0; 20 | } // main 21 | 22 | // end of testargv.c ... 23 | 24 | -------------------------------------------------------------------------------- /tests/testargv.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icculus/2ine/1ca194f39b6322d5c6cc1006616ed6a62f74c193/tests/testargv.exe -------------------------------------------------------------------------------- /tests/testargv16.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icculus/2ine/1ca194f39b6322d5c6cc1006616ed6a62f74c193/tests/testargv16.exe -------------------------------------------------------------------------------- /tests/testbeep.c: -------------------------------------------------------------------------------- 1 | #define INCL_DOS 2 | #include 3 | 4 | int main(void) 5 | { 6 | DosBeep(250, 100); 7 | DosBeep(300, 100); 8 | DosBeep(350, 100); 9 | DosBeep(400, 100); 10 | DosBeep(450, 100); 11 | DosBeep(475, 100); 12 | DosBeep(490, 100); 13 | DosBeep(497, 100); 14 | DosBeep(500, 100); 15 | return 0; 16 | } // main 17 | 18 | // end of testbeep.c ... 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/testbeep.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icculus/2ine/1ca194f39b6322d5c6cc1006616ed6a62f74c193/tests/testbeep.exe -------------------------------------------------------------------------------- /tests/testpm.c: -------------------------------------------------------------------------------- 1 | #define INCL_WININPUT 1 2 | #include 3 | 4 | static MRESULT APIENTRY winproc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) 5 | { 6 | switch (msg) { 7 | case WM_PAINT: { 8 | RECTL rect; 9 | HPS hps = WinBeginPaint(hwnd, NULLHANDLE, &rect); 10 | WinFillRect(hps, &rect, CLR_WHITE); 11 | WinEndPaint(hps); 12 | return 0; 13 | } 14 | 15 | case WM_BUTTON1CLICK: { // kill the app when the window is clicked on. 16 | WinPostMsg(hwnd, WM_QUIT, 0, 0); 17 | return 0; 18 | } 19 | } 20 | 21 | return WinDefWindowProc(hwnd, msg, mp1, mp2); 22 | } // winproc 23 | 24 | int main(int argc, char **argv) 25 | { 26 | HAB hab = WinInitialize(0); 27 | HMQ hmq = WinCreateMsgQueue(hab, 0); 28 | QMSG qmsg; 29 | HWND hwnd; 30 | 31 | WinRegisterClass(hab, "testpm", winproc, 0, 0); 32 | hwnd = WinCreateWindow(HWND_DESKTOP, "testpm", "testpm", WS_VISIBLE, 100, 100, 100, 100, 0, HWND_TOP, 0, NULL, NULL); 33 | 34 | while (WinGetMsg(hab, &qmsg, NULLHANDLE, 0, 0)) { 35 | WinDispatchMsg(hab, &qmsg); 36 | } 37 | 38 | WinDestroyWindow(hwnd); 39 | WinDestroyMsgQueue(hmq); 40 | WinTerminate(hab); 41 | 42 | return 0; 43 | } // main 44 | 45 | // end of testpm.c ... 46 | 47 | -------------------------------------------------------------------------------- /tests/testpm.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icculus/2ine/1ca194f39b6322d5c6cc1006616ed6a62f74c193/tests/testpm.exe -------------------------------------------------------------------------------- /tests/testtls.c: -------------------------------------------------------------------------------- 1 | #define INCL_DOS 2 | #define INCL_DOSERRORS 3 | #include 4 | #include 5 | #include 6 | 7 | static PULONG GAddr = NULL; 8 | static ULONG x = 0; 9 | 10 | static void APIENTRY threadFunc(ULONG arg) 11 | { 12 | const unsigned int t = (unsigned int) arg; 13 | DosSleep(t == 1 ? 500 : 1000); 14 | *GAddr = t * 100; 15 | //printf("thread %u set TLS value to %u\n", t, t * 100); 16 | //fflush(stdout); 17 | DosSleep(t == 1 ? 1000 : 50); 18 | x = *GAddr; 19 | //printf("thread %u sees TLS value of %u\n", t, (unsigned int) *GAddr); 20 | //fflush(stdout); 21 | } 22 | 23 | int main(void) 24 | { 25 | TID tid = 0; 26 | 27 | if (DosAllocThreadLocalMemory(1, &GAddr) != NO_ERROR) { 28 | fprintf(stderr, "DosAllocLocalThreadMemory failed\n"); 29 | return 1; 30 | } 31 | printf("the magic address is %p\n", GAddr); 32 | *GAddr = 10; 33 | printf("Main thread set TLS value to 10\n"); 34 | fflush(stdout); 35 | 36 | if (DosCreateThread(&tid, threadFunc, 1, 0, 0xFFFF) != NO_ERROR) { 37 | fprintf(stderr, "DosCreateThread 1 failed\n"); 38 | return 1; 39 | } 40 | if (DosCreateThread(&tid, threadFunc, 2, 0, 0xFFFF) != NO_ERROR) { 41 | fprintf(stderr, "DosCreateThread 2 failed\n"); 42 | return 1; 43 | } 44 | 45 | DosSleep(4000); 46 | 47 | printf("Main thread sees TLS value of %u\n", (unsigned int) *GAddr); 48 | fflush(stdout); 49 | 50 | DosFreeThreadLocalMemory(GAddr); 51 | 52 | return 0; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /tests/testtls.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icculus/2ine/1ca194f39b6322d5c6cc1006616ed6a62f74c193/tests/testtls.exe -------------------------------------------------------------------------------- /unimplemented.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | use warnings; 4 | use strict; 5 | use File::Basename; 6 | 7 | my %implemented = (); 8 | 9 | chdir(dirname(__FILE__)) or die("failed to chdir to script location: $!\n"); 10 | my $dirname = 'native'; 11 | opendir(DIRH, $dirname) or die("Failed to opendir '$dirname': $!\n"); 12 | 13 | while (readdir(DIRH)) { 14 | next if not /\-lx\.h\Z/; 15 | my $module = $_; 16 | my $header = "$dirname/$module"; 17 | open(IN, '<', $header) or die("Failed to open '$header' for reading: $!\n"); 18 | $module =~ s/\-lx\.h\Z//; 19 | $module =~ tr/a-z/A-Z/; 20 | 21 | while () { 22 | chomp; 23 | if (/\A\s*LX_NATIVE_EXPORT\d*\(.*?, (\d+)\)/) { 24 | $implemented{"$module\@$1"} = 1; 25 | } 26 | } 27 | 28 | close(IN); 29 | } 30 | 31 | while () { 32 | chomp; 33 | if (/\A.*? \((.*?\@\d+)\)/) { 34 | #my $isdef = defined $implemented{$1} ? "yes" : "no"; print("is '$1' defined? $isdef\n"); 35 | next if defined $implemented{$1}; 36 | } 37 | s/\A(...)32/$1/; # Change "Dos32" or whatnot to just "Dos" 38 | print("$_\n"); 39 | } 40 | 41 | # end of unimplemented.pl ... 42 | 43 | --------------------------------------------------------------------------------