forked from KolibriOS/kolibrios
226 lines
6.9 KiB
PHP
226 lines
6.9 KiB
PHP
|
; 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
|