Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2816 | clevermous | 1 | ; Platform-specific procedures for Windows. |
2 | |||
3 | ; Reallocate memory at pointer [start.buf] and size [start.allocated], |
||
4 | ; new size is in eax. |
||
5 | realloc: |
||
6 | push eax |
||
7 | stdcall [VirtualAlloc], 0, eax, MEM_COMMIT + MEM_RESERVE, PAGE_READWRITE |
||
8 | pop ecx |
||
9 | test eax, eax |
||
10 | jz nomemory |
||
11 | add [start.free], ecx |
||
12 | xchg ecx, [start.allocated] |
||
13 | sub [start.free], ecx |
||
14 | push esi edi |
||
15 | mov edi, eax |
||
16 | xchg eax, [start.buf] |
||
17 | shr ecx, 2 |
||
18 | jz .nothing |
||
19 | mov esi, eax |
||
20 | rep movsd |
||
21 | call free_eax |
||
22 | .nothing: |
||
23 | pop edi esi |
||
24 | ret |
||
25 | |||
26 | ; Read the next portion of input data to [start.buf]. |
||
27 | read: |
||
28 | push eax ; reserve space for *lpNumberOfBytesRead |
||
29 | mov ecx, esp |
||
30 | mov eax, [start.buf] |
||
31 | add eax, [start.allocated] |
||
32 | sub eax, [start.free] |
||
33 | stdcall [ReadFile], [start.in], eax, [start.free], ecx, 0 |
||
34 | test eax, eax |
||
35 | jz @f |
||
36 | .nothing: |
||
37 | pop eax |
||
38 | ret |
||
39 | @@: |
||
40 | ; ERROR_BROKEN_PIPE and ERROR_MORE_DATA are normal codes when dealing with pipes |
||
41 | call [GetLastError] |
||
42 | cmp eax, ERROR_BROKEN_PIPE |
||
43 | jz .nothing |
||
44 | cmp eax, ERROR_MORE_DATA |
||
45 | jz .nothing |
||
46 | pop eax |
||
47 | jmp readerr |
||
48 | |||
49 | ; Write output data: eax=pointer, edi=size. |
||
50 | write: |
||
51 | push eax |
||
52 | mov ecx, esp |
||
53 | stdcall [WriteFile], [start.out], eax, edi, ecx, 0 |
||
54 | test eax, eax |
||
55 | pop eax |
||
56 | jz writeerr |
||
57 | cmp eax, edi |
||
58 | jnz writeerr |
||
59 | ret |
||
60 | |||
61 | ; Parse command line, open input and output files. |
||
62 | get_params: |
||
63 | ; 1. Get the command line split to argv[] array. |
||
64 | call [GetCommandLineW] |
||
65 | push eax ; reserve space for *pNumArgs |
||
66 | stdcall [CommandLineToArgvW], eax, esp |
||
67 | pop ebx ; ebx = argc, eax = argv |
||
68 | push eax ; save argument for [LocalFree] |
||
69 | ; 2. Prepare for scanning, skipping argv[0]. |
||
70 | cmp ebx, 1 |
||
71 | jbe .noargs |
||
72 | dec ebx |
||
73 | lea esi, [eax+4] ; skip argv[0] |
||
74 | xor edi, edi ; no args parsed yet |
||
75 | ; 3. Parse loop. |
||
76 | .parse: |
||
77 | ; 3a. Get the next argument. |
||
78 | lodsd |
||
79 | ; 3b. Check whether it is a known option. |
||
80 | cmp dword [eax], '-' + 'e' * 65536 |
||
81 | jnz @f |
||
82 | cmp word [eax+4], 0 |
||
83 | jnz @f |
||
84 | ; 3c. If it is, modify flags and continue the loop. |
||
85 | mov [start.flags], 1 ; '-e' is given |
||
86 | jmp .nextarg |
||
87 | @@: |
||
88 | ; 3d. Otherwise, it is a name of input or output file. |
||
89 | ; edi keeps the count of names encountered before; |
||
90 | ; edi = 0 means this is input file, edi = 1 - output file, |
||
91 | ; otherwise this is third arg, which is an error |
||
92 | cmp edi, 1 |
||
93 | ja .toomanyargs |
||
94 | ; 3e. Some parameters of CreateFileW differ for input and output. Setup them. |
||
95 | mov ecx, GENERIC_WRITE |
||
96 | mov edx, CREATE_ALWAYS |
||
97 | jz @f |
||
98 | add ecx, ecx ; GENERIC_READ |
||
99 | inc edx ; OPEN_EXISTING |
||
100 | @@: |
||
101 | ; 3f. Open/create the file, save the handle. |
||
102 | stdcall [CreateFileW], eax, ecx, FILE_SHARE_READ+FILE_SHARE_DELETE, 0, edx, FILE_ATTRIBUTE_NORMAL, 0 |
||
103 | cmp eax, INVALID_HANDLE_VALUE |
||
104 | jz .fileerr |
||
105 | mov [start.in+edi*4], eax |
||
106 | inc edi |
||
107 | .nextarg: |
||
108 | dec ebx |
||
109 | jnz .parse |
||
110 | .noargs: |
||
111 | ; 4. End of command line reached. If input and/or output was not given, use defaults. |
||
112 | test edi, edi |
||
113 | jnz .hasinput |
||
114 | stdcall [GetStdHandle], STD_INPUT_HANDLE |
||
115 | mov [start.in], eax |
||
116 | .hasinput: |
||
117 | cmp edi, 1 |
||
118 | ja .hasoutput |
||
119 | stdcall [GetStdHandle], STD_OUTPUT_HANDLE |
||
120 | mov [start.out], eax |
||
121 | .hasoutput: |
||
122 | ; 5. Free memory allocated in step 1 and return. |
||
123 | call [LocalFree] |
||
124 | ret |
||
125 | .toomanyargs: |
||
126 | call [LocalFree] |
||
127 | jmp information |
||
128 | .fileerr: |
||
129 | call [LocalFree] |
||
130 | test edi, edi |
||
131 | jz in_openerr |
||
132 | jmp out_openerr |
||
133 | |||
134 | ; Exit, return code is in al. |
||
135 | exit: |
||
136 | movzx eax, al |
||
137 | push eax ; save return code for [ExitProcess] |
||
138 | mov eax, [start.buf] |
||
139 | test eax, eax |
||
140 | jz @f |
||
141 | call free_eax |
||
142 | @@: |
||
143 | stdcall [CloseHandle], [start.in] |
||
144 | stdcall [CloseHandle], [start.out] |
||
145 | call [ExitProcess] |
||
146 | |||
147 | ; Output the message given in esi to stderr. |
||
148 | sayerr: |
||
149 | stdcall [GetStdHandle], STD_ERROR_HANDLE |
||
150 | push eax |
||
151 | mov ecx, esp |
||
152 | movzx edx, byte [esi-1] |
||
153 | stdcall [WriteFile], eax, esi, edx, ecx, 0 |
||
154 | pop ecx |
||
155 | ret |
||
156 | |||
157 | ; Helper procedure for realloc and exit. |
||
158 | free_eax: |
||
159 | stdcall [VirtualFree], eax, 0, MEM_RELEASE |
||
160 | ret |
||
161 | |||
162 | ; Get environment variable esi (ebx-relative pointer) to the buffer, |
||
163 | ; expanding it if needed. |
||
164 | get_environment_variable: |
||
165 | lea eax, [edi+ebx] |
||
166 | lea ecx, [esi+ebx] |
||
167 | stdcall [GetEnvironmentVariableA], ecx, eax, [start.free] |
||
168 | ; GetEnvironmentVariable returns one of following values: |
||
169 | ; * if all is ok: number of characters copied to the buffer, |
||
170 | ; not including terminating zero |
||
171 | ; * if buffer size is too small: number of characters required in the buffer, |
||
172 | ; including terminating zero |
||
173 | ; * if environment variable not found: zero |
||
174 | ; We treat the last case the same as first one. |
||
175 | cmp eax, [start.free] |
||
176 | jae .resize |
||
177 | inc eax ; include terminating zero |
||
178 | add edi, eax |
||
179 | sub [start.free], eax |
||
180 | mov byte [edi+ebx-1], 0 ; force zero-terminated or empty string |
||
181 | ret |
||
182 | .resize: |
||
183 | ; esi can be inside the buffer or outside the buffer; |
||
184 | ; we must not correct it in the first case, |
||
185 | ; but advance relative to new value of ebx in the second one. |
||
186 | mov ecx, esi |
||
187 | cmp esi, [start.allocated] |
||
188 | jb @f |
||
189 | add esi, ebx |
||
190 | @@: |
||
191 | stdcall alloc_in_buf, eax |
||
192 | cmp esi, ecx |
||
193 | jz get_environment_variable |
||
194 | sub esi, ebx |
||
195 | jmp get_environment_variable |
||
196 | |||
197 | ; Test whether a file with name [.testname] exists. |
||
198 | ; Returns eax<0 if not, nonzero otherwise. |
||
199 | test_file_exists: |
||
200 | mov eax, [start.testname] |
||
201 | add eax, ebx |
||
202 | stdcall [GetFileAttributesA], eax |
||
203 | inc eax |
||
204 | ret |
||
205 | |||
206 | ; Imports |
||
207 | align 4 |
||
208 | data import |
||
209 | library kernel32,'kernel32.dll',shell32,'shell32.dll' |
||
210 | import kernel32, \ |
||
211 | GetLastError, 'GetLastError', \ |
||
212 | ExitProcess, 'ExitProcess', \ |
||
213 | VirtualAlloc, 'VirtualAlloc', \ |
||
214 | VirtualFree, 'VirtualFree', \ |
||
215 | LocalFree, 'LocalFree', \ |
||
216 | GetStdHandle, 'GetStdHandle', \ |
||
217 | CreateFileW, 'CreateFileW', \ |
||
218 | GetFileAttributesA, 'GetFileAttributesA', \ |
||
219 | ReadFile, 'ReadFile', \ |
||
220 | WriteFile, 'WriteFile', \ |
||
221 | CloseHandle, 'CloseHandle', \ |
||
222 | GetCommandLineW, 'GetCommandLineW', \ |
||
223 | GetEnvironmentVariableA, 'GetEnvironmentVariableA' |
||
224 | import shell32, CommandLineToArgvW, 'CommandLineToArgvW' |
||
225 | end data0> |