kolibrios/data/common/fasmdep/windows_sys.inc

226 lines
6.9 KiB
PHP
Raw Permalink Normal View History

; Platform-specific procedures for Windows.
; Reallocate memory at pointer [start.buf] and size [start.allocated],
; new size is in eax.
realloc:
push eax
stdcall [VirtualAlloc], 0, eax, MEM_COMMIT + MEM_RESERVE, PAGE_READWRITE
pop ecx
test eax, eax
jz nomemory
add [start.free], ecx
xchg ecx, [start.allocated]
sub [start.free], ecx
push esi edi
mov edi, eax
xchg eax, [start.buf]
shr ecx, 2
jz .nothing
mov esi, eax
rep movsd
call free_eax
.nothing:
pop edi esi
ret
; Read the next portion of input data to [start.buf].
read:
push eax ; reserve space for *lpNumberOfBytesRead
mov ecx, esp
mov eax, [start.buf]
add eax, [start.allocated]
sub eax, [start.free]
stdcall [ReadFile], [start.in], eax, [start.free], ecx, 0
test eax, eax
jz @f
.nothing:
pop eax
ret
@@:
; ERROR_BROKEN_PIPE and ERROR_MORE_DATA are normal codes when dealing with pipes
call [GetLastError]
cmp eax, ERROR_BROKEN_PIPE
jz .nothing
cmp eax, ERROR_MORE_DATA
jz .nothing
pop eax
jmp readerr
; Write output data: eax=pointer, edi=size.
write:
push eax
mov ecx, esp
stdcall [WriteFile], [start.out], eax, edi, ecx, 0
test eax, eax
pop eax
jz writeerr
cmp eax, edi
jnz writeerr
ret
; Parse command line, open input and output files.
get_params:
; 1. Get the command line split to argv[] array.
call [GetCommandLineW]
push eax ; reserve space for *pNumArgs
stdcall [CommandLineToArgvW], eax, esp
pop ebx ; ebx = argc, eax = argv
push eax ; save argument for [LocalFree]
; 2. Prepare for scanning, skipping argv[0].
cmp ebx, 1
jbe .noargs
dec ebx
lea esi, [eax+4] ; skip argv[0]
xor edi, edi ; no args parsed yet
; 3. Parse loop.
.parse:
; 3a. Get the next argument.
lodsd
; 3b. Check whether it is a known option.
cmp dword [eax], '-' + 'e' * 65536
jnz @f
cmp word [eax+4], 0
jnz @f
; 3c. If it is, modify flags and continue the loop.
mov [start.flags], 1 ; '-e' is given
jmp .nextarg
@@:
; 3d. Otherwise, it is a name of input or output file.
; edi keeps the count of names encountered before;
; edi = 0 means this is input file, edi = 1 - output file,
; otherwise this is third arg, which is an error
cmp edi, 1
ja .toomanyargs
; 3e. Some parameters of CreateFileW differ for input and output. Setup them.
mov ecx, GENERIC_WRITE
mov edx, CREATE_ALWAYS
jz @f
add ecx, ecx ; GENERIC_READ
inc edx ; OPEN_EXISTING
@@:
; 3f. Open/create the file, save the handle.
stdcall [CreateFileW], eax, ecx, FILE_SHARE_READ+FILE_SHARE_DELETE, 0, edx, FILE_ATTRIBUTE_NORMAL, 0
cmp eax, INVALID_HANDLE_VALUE
jz .fileerr
mov [start.in+edi*4], eax
inc edi
.nextarg:
dec ebx
jnz .parse
.noargs:
; 4. End of command line reached. If input and/or output was not given, use defaults.
test edi, edi
jnz .hasinput
stdcall [GetStdHandle], STD_INPUT_HANDLE
mov [start.in], eax
.hasinput:
cmp edi, 1
ja .hasoutput
stdcall [GetStdHandle], STD_OUTPUT_HANDLE
mov [start.out], eax
.hasoutput:
; 5. Free memory allocated in step 1 and return.
call [LocalFree]
ret
.toomanyargs:
call [LocalFree]
jmp information
.fileerr:
call [LocalFree]
test edi, edi
jz in_openerr
jmp out_openerr
; Exit, return code is in al.
exit:
movzx eax, al
push eax ; save return code for [ExitProcess]
mov eax, [start.buf]
test eax, eax
jz @f
call free_eax
@@:
stdcall [CloseHandle], [start.in]
stdcall [CloseHandle], [start.out]
call [ExitProcess]
; Output the message given in esi to stderr.
sayerr:
stdcall [GetStdHandle], STD_ERROR_HANDLE
push eax
mov ecx, esp
movzx edx, byte [esi-1]
stdcall [WriteFile], eax, esi, edx, ecx, 0
pop ecx
ret
; Helper procedure for realloc and exit.
free_eax:
stdcall [VirtualFree], eax, 0, MEM_RELEASE
ret
; Get environment variable esi (ebx-relative pointer) to the buffer,
; expanding it if needed.
get_environment_variable:
lea eax, [edi+ebx]
lea ecx, [esi+ebx]
stdcall [GetEnvironmentVariableA], ecx, eax, [start.free]
; GetEnvironmentVariable returns one of following values:
; * if all is ok: number of characters copied to the buffer,
; not including terminating zero
; * if buffer size is too small: number of characters required in the buffer,
; including terminating zero
; * if environment variable not found: zero
; We treat the last case the same as first one.
cmp eax, [start.free]
jae .resize
inc eax ; include terminating zero
add edi, eax
sub [start.free], eax
mov byte [edi+ebx-1], 0 ; force zero-terminated or empty string
ret
.resize:
; esi can be inside the buffer or outside the buffer;
; we must not correct it in the first case,
; but advance relative to new value of ebx in the second one.
mov ecx, esi
cmp esi, [start.allocated]
jb @f
add esi, ebx
@@:
stdcall alloc_in_buf, eax
cmp esi, ecx
jz get_environment_variable
sub esi, ebx
jmp get_environment_variable
; Test whether a file with name [.testname] exists.
; Returns eax<0 if not, nonzero otherwise.
test_file_exists:
mov eax, [start.testname]
add eax, ebx
stdcall [GetFileAttributesA], eax
inc eax
ret
; Imports
align 4
data import
library kernel32,'kernel32.dll',shell32,'shell32.dll'
import kernel32, \
GetLastError, 'GetLastError', \
ExitProcess, 'ExitProcess', \
VirtualAlloc, 'VirtualAlloc', \
VirtualFree, 'VirtualFree', \
LocalFree, 'LocalFree', \
GetStdHandle, 'GetStdHandle', \
CreateFileW, 'CreateFileW', \
GetFileAttributesA, 'GetFileAttributesA', \
ReadFile, 'ReadFile', \
WriteFile, 'WriteFile', \
CloseHandle, 'CloseHandle', \
GetCommandLineW, 'GetCommandLineW', \
GetEnvironmentVariableA, 'GetEnvironmentVariableA'
import shell32, CommandLineToArgvW, 'CommandLineToArgvW'
end data