Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2816 clevermous 1
; This program parses .fas file generated by fasm
2
; and prints the list of dependencies for make.
3
; Usage: fasmdep [-e] [ []].
4
; If input file is not given, the program reads from stdin.
5
; If output file is not given, the program writes to stdout.
6
; If the option -e is given, the program also creates an empty
7
; goal for every dependency, this prevents make errors when
8
; files are renamed.
9
 
10
; This definition controls the choice of platform-specific code.
11
;define OS WINDOWS
12
define OS LINUX
13
 
14
; Program header.
15
match =WINDOWS,OS { include 'windows_header.inc' }
16
match =LINUX,OS { include 'linux_header.inc' }
17
 
18
include 'fas.inc'
19
 
20
; Main code
21
start:
22
; 1. Setup stack frame, zero-initialize all local variables.
23
virtual at ebp - .localsize
24
.begin:
25
.flags          dd      ?       ; 1 if '-e' is given
26
.in             dd      ?       ; handle of input file
27
.out            dd      ?       ; handle of output file
28
.buf            dd      ?       ; pointer to data of .fas file
29
.allocated      dd      ?       ; number of bytes allocated for .buf
30
.free           dd      ?       ; number of bytes free in .buf
31
.outstart       dd      ?       ; offset in .buf for start of data to output
32
.names          dd      ?       ; offset in .buf for start of output names
33
.include        dd      ?       ; offset in .buf to value of %INCLUDE%
34
.testname       dd      ?       ; offset in .buf for start of current file name
35
.prevfile       dd      ?       ; offset in .buf for previous included file name
36
.prevfilefrom   dd      ?       ; offset in .buf for .asm/.inc for .prevfile
37
.localsize = $ - .begin
38
match =LINUX,OS {
39
.argc           dd      ?
40
.argv:
41
}
42
end virtual
43
 
44
        mov     ebp, esp
45
        xor     eax, eax
46
repeat .localsize / 4
47
        push    eax
48
end repeat
49
; 2. Call the parser of the command line.
50
        call    get_params
51
; 3. Load the input file.
52
; Note that stdin can be a pipe,
53
; useful in bash-construction "fasm input.asm -s >(fasmdep > input.Po)",
54
; so its size is not always known in the beginning.
55
; So, we must read input file in portions, reallocating memory if needed.
56
.readloop:
57
; 3a. If the size is less than 32768 bytes, reallocate buffer.
58
; Otherwise, goto 3c.
59
        cmp     [.free], 32768
60
        jae     .norealloc
61
; 3b. Reallocate buffer.
62
; Start with 65536 bytes and then double the size every time.
63
        mov     eax, 65536
64
        mov     ecx, [.allocated]
65
        add     ecx, ecx
66
        jz      @f
67
        mov     eax, ecx
68
@@:
69
        call    realloc
70
.norealloc:
71
; 3c. Read the next portion.
72
        call    read
73
        sub     [.free], eax
74
        test    eax, eax
75
        jnz     .readloop
76
; 4. Sanity checks.
77
; We don't use .section_* and .symref_*, so allow them to be absent.
78
        mov     edi, [.allocated]
79
        sub     edi, [.free]
80
; Note that edi = number of bytes which were read
81
; and simultaneously pointer to free space in the buffer relative to [.buf].
82
        cmp     edi, fas_header.section_offs
83
        jb      badfile
84
        mov     ebx, [.buf]
85
        cmp     [ebx+fas_header.signature], FAS_SIGNATURE
86
        jnz     badfile
87
        cmp     [ebx+fas_header.headersize], fas_header.section_offs
88
        jb      badfile
89
; 5. Get %INCLUDE% environment variable, it will be useful.
90
        mov     [.include], edi
91
        mov     esi, include_variable
92
        sub     esi, ebx
93
        call    get_environment_variable
94
; 6. Start writing dependencies: copy output and input files.
95
        mov     [.outstart], edi
96
; 6a. Copy output name.
97
        mov     esi, [ebx+fas_header.output]
98
        call    copy_asciiz_escaped
99
; 6b. Write ": ".
100
        stdcall alloc_in_buf, 2
101
        mov     word [edi+ebx], ': '
102
        inc     edi
103
        inc     edi
104
; 6c. Copy input name.
105
        mov     [.names], edi
106
        mov     esi, [ebx+fas_header.input]
107
        call    copy_asciiz_escaped
108
; 7. Scan for 'include' dependencies.
109
; 7a. Get range for scanning.
110
        mov     edx, [ebx+fas_header.preproc_size]
111
        mov     esi, [ebx+fas_header.preproc_offs]
112
        add     edx, esi
113
.include_loop:
114
; 7b. Loop over preprocessed lines in the range.
115
        cmp     esi, edx
116
        jae     .include_done
117
; 7c. For every line, ignore header and do internal loop over tokens.
118
        add     esi, preproc_line_header.contents
119
.include_loop_int:
120
; There are five types of tokens:
121
; 1) "start preprocessor data" with code ';'  
122
; 2) "quoted string" with code '"'  
123
; 3) "word" with code 1Ah  
124
; 4) one-byte tokens like "+", "(" and so on
125
; 5) "end-of-line" token with code 0.
126
        mov     al, [esi+ebx]
127
        inc     esi
128
; 7d. First, check token type parsing the first byte.
129
; For preprocessor tokens, continue to 7e.
130
; For quoted strings, go to 7g.
131
; For words, go to 7h.
132
; For end-of-line, exit the internal loop, continue the external loop.
133
; Otherwise, just continue the internal loop.
134
        cmp     al, ';'
135
        jnz     .notprep
136
; 7e. For "include" tokens length=7, token is "include", the next token is
137
; quoted string.
138
; These tokens are handled in 7f, other preprocessor tokens in 7g.
139
        cmp     byte [esi+ebx], 7
140
        jnz     .notinclude
141
        cmp     dword [esi+ebx+1], 'incl'
142
        jnz     .notinclude
143
        cmp     dword [esi+ebx+5], 'ude"'
144
        jnz     .notinclude
145
; 7f. Skip over end of this token and the type byte of the next token;
146
; this gives the pointer to length-prefixed string, which should be added
147
; to dependencies. Note that doing that skips that string,
148
; so after copying just continue the internal loop.
149
        add     esi, 9
150
        call    add_separator
151
        call    copy_name_escaped
152
        jmp     .include_loop_int
153
.quoted:
154
; 7g. To skip a word, load the dword length and add it to pointer.
155
        add     esi, [esi+ebx]
156
        add     esi, 4
157
        jmp     .include_loop_int
158
.notinclude:
159
; 7h. To skip this token, load the byte length and add it to pointer.
160
; Note that word tokens and preprocessor tokens have a similar structure,
161
; so both are handled here.
162
        movzx   eax, byte [esi+ebx]
163
        lea     esi, [esi+eax+1]
164
        jmp     .include_loop_int
165
.notprep:
166
        cmp     al, 1Ah
167
        jz      .notinclude
168
        cmp     al, '"'
169
        jz      .quoted
170
        test    al, al
171
        jnz     .include_loop_int
172
        jmp     .include_loop
173
.include_done:
174
; 8. Scan for 'file' dependencies.
175
; 8a. Get range for scanning.
176
; Note that fas_header.asm_size can be slighly greater than the
177
; real size, so we break from the loop when there is no space left
178
; for the entire asm_row structure, not when .asm_size is exactly reached.
179
        mov     esi, [ebx+fas_header.asm_offs]
180
        mov     edx, [ebx+fas_header.asm_size]
181
        add     edx, esi
182
        sub     edx, asm_row.sizeof
183
        push    edx
184
        jc      .file_done
185
.file_loop:
186
; 8b. Loop over assembled lines in the range.
187
        cmp     esi, [esp]
188
        ja      .file_done
189
; 8c. For every assembled line, look at first token;
190
; go to 8d for token 'file',
191
; go to 8e for token 'format',
192
; go to 8f for token 'section',
193
; continue the loop otherwise.
194
        mov     eax, [esi+ebx+asm_row.preproc_offs]
195
        add     eax, [ebx+fas_header.preproc_offs]
196
        cmp     byte [eax+ebx+preproc_line_header.contents], 1Ah
197
        jnz     .file_next
198
        movzx   ecx, byte [eax+ebx+preproc_line_header.contents+1]
199
        cmp     cl, 4
200
        jnz     .file_no_file
201
        cmp     dword [eax+ebx+preproc_line_header.contents+2], 'file'
202
        jnz     .file_no_file4
203
; 8d. For lines starting with 'file' token, loop over tokens and get names.
204
; Note that there can be several names in one line.
205
; Parsing of tokens is similar to step 5 with the difference that
206
; preprocessor token stops processing: 'file' directives are processed
207
; in assembler stage.
208
; We save/restore esi since it is used for another thing in the internal loop;
209
; we push eax, which currently contains ebx-relative pointer to
210
; preproc_line_header, to be able to access it from resolve_name.
211
        push    esi eax
212
        lea     esi, [eax+preproc_line_header.contents+6]
213
.file_loop_int:
214
        mov     al, [esi+ebx]
215
        inc     esi
216
        test    al, al
217
        jz      .file_loop_int_done
218
        cmp     al, ';'
219
        jz      .file_loop_int_done
220
        cmp     al, 1Ah
221
        jz      .fileword
222
        cmp     al, '"'
223
        jnz     .file_loop_int
224
        call    resolve_name
225
        add     esi, [esi+ebx-4]
226
        jmp     .file_loop_int
227
.fileword:
228
        movzx   eax, byte [esi+ebx]
229
        lea     esi, [esi+eax+1]
230
        jmp     .file_loop_int
231
.file_loop_int_done:
232
        pop     eax esi
233
        jmp     .file_next
234
.file_no_file4:
235
        cmp     dword [eax+ebx+preproc_line_header.contents+2], 'data'
236
        jnz     .file_next
237
        jmp     .file_scan_from
238
.file_no_file:
239
        cmp     cl, 6
240
        jnz     .file_no_format
241
        cmp     dword [eax+ebx+preproc_line_header.contents+2], 'form'
242
        jnz     .file_no_format
243
        cmp     word [eax+ebx+preproc_line_header.contents+6], 'at'
244
        jnz     .file_no_format
245
; 8e. For lines starting with 'format' token, loop over tokens and look for stub name.
246
; Note that there can be another quoted string, namely file extension;
247
; stub name always follows the token 'on'.
248
        mov     edx, TokenOn
249
        call    scan_after_word
250
        jmp     .file_next
251
.file_no_format:
252
        cmp     cl, 7
253
        jnz     .file_no_section
254
        cmp     dword [eax+ebx+preproc_line_header.contents+2], 'sect'
255
        jnz     .file_no_section
256
        mov     edx, dword [eax+ebx+preproc_line_header.contents+6]
257
        and     edx, 0FFFFFFh
258
        cmp     edx, 'ion'
259
        jnz     .file_no_section
260
.file_scan_from:
261
        mov     edx, TokenFrom
262
        call    scan_after_word
263
.file_no_section:
264
.file_next:
265
        add     esi, asm_row.sizeof
266
        jmp     .file_loop
267
.file_done:
268
        pop     edx
269
; 9. Write result.
270
; 9a. Append two newlines to the end of buffer.
271
        stdcall alloc_in_buf, 2
272
        mov     word [edi+ebx], 10 * 101h
273
        inc     edi
274
        inc     edi
275
; 9b. If '-e' option was given, duplicate dependencies list as fake goals
276
; = copy all of them and append ":\n\n".
277
        cmp     [.flags], 0
278
        jz      .nodup
279
        lea     ecx, [edi+1]
280
        mov     esi, [.names]
281
        sub     ecx, esi
282
        stdcall alloc_in_buf, ecx
283
        add     esi, ebx
284
        add     edi, ebx
285
        rep     movsb
286
        mov     byte [edi-3], ':'
287
        mov     word [edi-2], 10 * 101h
288
        sub     edi, ebx
289
.nodup:
290
; 9c. Write to output file.
291
        mov     eax, [.outstart]
292
        sub     edi, eax
293
        add     eax, ebx
294
        call    write
295
; 10. Exit.
296
        xor     eax, eax
297
        call    exit
298
 
299
; Helper procedure for steps 8e and 8f of main algorithm.
300
; Looks for quoted strings after given word in edx.
301
scan_after_word:
302
        push    esi eax
303
        lea     esi, [eax+preproc_line_header.contents+2+ecx]
304
.loop:
305
        xor     ecx, ecx
306
.loop_afterword:
307
        mov     al, [esi+ebx]
308
        inc     esi
309
        test    al, al
310
        jz      .loop_done
311
        cmp     al, ';'
312
        jz      .loop_done
313
        cmp     al, 1Ah
314
        jz      .word
315
        cmp     al, '"'
316
        jnz     .loop
317
        test    ecx, ecx
318
        jz      .skip_quoted
319
        call    resolve_name
320
.loop_done:
321
        pop     eax esi
322
        ret
323
.skip_quoted:
324
        add     esi, [esi+ebx]
325
        add     esi, 4
326
        jmp     .loop
327
.word:
328
        movzx   ecx, byte [esi+ebx]
329
        lea     esi, [esi+ecx+1]
330
        cmp     cl, byte [edx]
331
        jnz     .loop
332
        push    esi edi
333
        add     esi, ebx
334
        sub     esi, ecx
335
        lea     edi, [edx+1]
336
        repz    cmpsb
337
        pop     edi esi
338
        jnz     .loop
339
        dec     ecx
340
        jmp     .loop_afterword
341
 
342
; Helper procedure for step 6 of the main procedure.
343
; Copies the ASCIIZ name from strings section to the buffer.
344
copy_asciiz_escaped:
345
        add     esi, [ebx+fas_header.strings_offs]
346
.loop:
347
        mov     al, [esi+ebx]
348
        test    al, al
349
        jz      .nothing
350
        call    copy_char_escaped
351
        jmp     .loop
352
.nothing:
353
        ret
354
 
355
; Helper procedure for step 7 of the main procedure.
356
; Copies the name with known length to the buffer.
357
copy_name_escaped:
358
        mov     ecx, [esi+ebx]
359
        add     esi, 4
360
        test    ecx, ecx
361
        jz      .nothing
362
        push    ecx
363
.loop:
364
        mov     al, [esi+ebx]
365
        call    copy_char_escaped
366
        dec     dword [esp]
367
        jnz     .loop
368
        pop     ecx
369
.nothing:
370
        ret
371
 
372
; Helper procedure for steps 7 and 8 of the main procedure.
373
; Writes separator of file names in output = " \\\n".
374
add_separator:
375
        stdcall alloc_in_buf, 3
376
        mov     word [edi+ebx], ' \'
377
        mov     byte [edi+ebx+2], 10
378
        add     edi, 3
379
        ret
380
 
381
; Helper procedure for step 7 of the main procedure.
382
; Resolves the path to 'file' dependency and copies
383
; the full name to the buffer.
384
resolve_name:
385
; FASM uses the following order to search for referenced files:
386
; * path of currently assembling file, which may be .asm or .inc
387
; * paths from %INCLUDE% for versions >= 1.70
388
; * current directory = file name is taken as is, without prepending dir name
389
; We mirror this behaviour, trying to find an existing file somewhere.
390
; There can be following reasons for the file can not be found anywhere:
391
; * it has been deleted between compilation and our actions
392
; * it didn't exist at all, compilation has failed
393
; * we are running in environment different from fasm environment.
394
; Assume that the last reason is most probable and that invalid dependency
395
; is better than absent dependency (it is easier to fix an explicit error
396
; than a silent one) and output file name without prepending dir name,
397
; as in the last case. Actually, we even don't need to test existence
398
; of the file in the current directory.
399
        add     esi, 4  ; skip string length
400
; 1. Get ebx-relative pointer to preproc_line_header, see the comment in start.7d
401
        mov     eax, [esp+4]
402
; 2. Get the path to currently processing file.
403
        push    esi
404
.getpath:
405
        test    byte [eax+ebx+preproc_line_header.line_number+3], 80h
406
        jz      @f
407
        mov     eax, [eax+ebx+preproc_line_header.line_offset]
408
        add     eax, [ebx+fas_header.preproc_offs]
409
        jmp     .getpath
410
@@:
411
        mov     edx, [eax+ebx+preproc_line_header.source_name]
412
        test    edx, edx
413
        jz      .frommain
414
        add     edx, [ebx+fas_header.preproc_offs]
415
        jmp     @f
416
.frommain:
417
        mov     edx, [ebx+fas_header.input]
418
        add     edx, [ebx+fas_header.strings_offs]
419
@@:
420
; 3. Check that it is not a duplicate of the previous dependency.
421
; 3a. Compare preprocessor units.
422
        cmp     edx, [start.prevfilefrom]
423
        jnz     .nodup
424
; 3b. Compare string lengths.
425
        mov     eax, [start.prevfile]
426
        mov     ecx, [eax+ebx-4]
427
        cmp     ecx, [esi+ebx-4]
428
        jnz     .nodup
429
; 3c. Compare string contents.
430
        push    esi edi
431
        lea     edi, [eax+ebx]
432
        add     esi, ebx
433
        rep     cmpsb
434
        pop     edi esi
435
        jnz     .nodup
436
; 3d. It is duplicate, just return.
437
        pop     esi
438
        ret
439
.nodup:
440
; 3e. It is not duplicate. Output separator.
441
        mov     [start.prevfilefrom], edx
442
        mov     [start.prevfile], esi
443
        call    add_separator
444
; 4. Cut the last component of the path found in step 2.
445
        mov     ecx, edx
446
        mov     esi, edx
447
.scanpath:
448
        mov     al, [edx+ebx]
449
        test    al, al
450
        jz      .scandone
451
        cmp     al, '/'
452
        jz      .slash
453
        cmp     al, '\'
454
        jnz     .scannext
455
.slash:
456
        lea     ecx, [edx+1]
457
.scannext:
458
        inc     edx
459
        jmp     .scanpath
460
.scandone:
461
        sub     ecx, esi
462
; 5. Try path found in step 4. If found, go to step 8.
463
        mov     [start.testname], edi
464
        stdcall copy_string, esi, ecx
465
        pop     esi
466
        call    expand_environment
467
        call    test_file_exists
468
        test    eax, eax
469
        jns     .found
470
        call    revert_testname
471
; 6. Try each of include paths. For every path, if file is found, go to step 8.
472
; Otherwise, continue loop over include path.
473
; Skip this step before 1.70.
474
        cmp     [ebx+fas_header.major], 1
475
        ja      .checkenv
476
        jb      .nocheckenv
477
        cmp     [ebx+fas_header.minor], 70
478
        jb      .nocheckenv
479
.checkenv:
480
        mov     ecx, [start.include]
481
.includeloop_ext:
482
        mov     eax, ecx
483
.includeloop_int:
484
        cmp     byte [eax+ebx], 0
485
        jz      @f
486
        cmp     byte [eax+ebx], ';'
487
        jz      @f
488
        inc     eax
489
        jmp     .includeloop_int
490
@@:
491
        push    eax
492
        sub     eax, ecx
493
        jz      @f
494
        stdcall copy_string, ecx, eax
495
        cmp     byte [edi+ebx-1], '/'
496
        jz      .hasslash
497
@@:
498
        stdcall alloc_in_buf, 1
499
        mov     byte [edi+ebx], '/'
500
        inc     edi
501
.hasslash:
502
        call    expand_environment
503
        call    test_file_exists
504
        pop     ecx
505
        test    eax, eax
506
        jns     .found
507
        call    revert_testname
508
        cmp     byte [ecx+ebx], 0
509
        jz      .notfound
510
        inc     ecx
511
        cmp     byte [ecx+ebx], 0
512
        jnz     .includeloop_ext
513
.nocheckenv:
514
.notfound:
515
; 7. File not found neither near the current preprocessor unit nor in %INCLUDE%.
516
; Assume that it is in the current directory.
517
        call    expand_environment
518
.found:
519
; 8. Currently we have file name from [start.testname] to edi;
520
; it is zero-terminated and not space-escaped. Fix both issues.
521
        dec     edi
522
        inc     [start.free]
523
        push    esi
524
        mov     edx, [start.testname]
525
.escapeloop:
526
        cmp     edx, edi
527
        jae     .escapedone
528
        cmp     byte [edx+ebx], ' '
529
        jnz     .noescape
530
        stdcall alloc_in_buf, 1
531
        mov     ecx, edi
532
        sub     ecx, edx
533
        push    edi
534
        add     edi, ebx
535
        lea     esi, [edi-1]
536
        std
537
        rep     movsb
538
        cld
539
        pop     edi
540
        inc     edi
541
        mov     byte [edx+ebx], '\'
542
        inc     edx
543
.noescape:
544
        inc     edx
545
        jmp     .escapeloop
546
.escapedone:
547
        pop     esi
548
        ret
549
 
550
; Helper procedure for resolve_name.
551
; Allocates space in the buffer and appends the given string to the buffer.
552
copy_string:
553
        mov     eax, [esp+8]
554
        test    eax, eax
555
        jz      .nothing
556
        stdcall alloc_in_buf, eax
557
        mov     ecx, [esp+4]
558
.copy:
559
        mov     al, [ecx+ebx]
560
        inc     ecx
561
        cmp     al, '\'
562
        jnz     @f
563
        mov     al, '/'
564
@@:
565
        mov     [edi+ebx], al
566
        inc     edi
567
        dec     dword [esp+8]
568
        jnz     .copy
569
.nothing:
570
        ret     8
571
 
572
; Helper procedure for resolve_name. Undoes appending of last file name.
573
revert_testname:
574
        add     [start.free], edi
575
        mov     edi, [start.testname]
576
        sub     [start.free], edi
577
        ret
578
 
579
; Helper procedure for resolve_name. Copies string from esi to edi,
580
; expanding environment variables.
581
expand_environment:
582
; 1. Save esi to restore it in the end of function.
583
        push    esi
584
; 2. Push string length to the stack to be used as a variable.
585
        pushd   [esi+ebx-4]
586
; 3. Scan loop.
587
.scan:
588
; 3a. Scan for '%' sign.
589
        call    find_percent
590
.justcopy:
591
; 3b. Copy the part from the beginning of current portion to '%' sign,
592
; advance pointer to '%' sign, or end-of-string if no '%' found.
593
        push    eax
594
        sub     eax, esi
595
        stdcall copy_string, esi, eax
596
        pop     esi
597
; 3c. If string has ended, break from the loop.
598
        cmp     dword [esp], 0
599
        jz      .scandone
600
; 3d. Advance over '%' sign.
601
        inc     esi
602
        dec     dword [esp]
603
; 3e. Find paired '%'.
604
        call    find_percent
605
; 3f. If there is no paired '%', just return to 3b and copy remaining data,
606
; including skipped '%'; after that, 3c would break from the loop.
607
        dec     esi
608
        cmp     dword [esp], 0
609
        jz      .justcopy
610
; 3g. Otherwise, get the value of environment variable.
611
; Since get_environment_variable requires zero-terminated string
612
; and returns zero-terminated string, temporarily overwrite trailing '%'
613
; and ignore last byte in returned string.
614
; Also convert any backslashes to forward slashes.
615
        inc     esi
616
        mov     byte [eax+ebx], 0
617
        push    eax
618
        push    edi
619
        call    get_environment_variable
620
        dec     edi
621
        inc     [start.free]
622
        pop     eax
623
.replaceslash:
624
        cmp     eax, edi
625
        jz      .replaceslash_done
626
        cmp     byte [eax+ebx], '\'
627
        jnz     @f
628
        mov     byte [eax+ebx], '/'
629
@@:
630
        inc     eax
631
        jmp     .replaceslash
632
.replaceslash_done:
633
        pop     esi
634
        mov     byte [esi+ebx], '%'
635
; 3h. Advance over trailing '%'.
636
        inc     esi
637
        dec     dword [esp]
638
; 3i. Continue the loop.
639
        jmp     .scan
640
.scandone:
641
; 4. Zero-terminate resulting string.
642
        stdcall alloc_in_buf, 1
643
        mov     byte [edi+ebx], 0
644
        inc     edi
645
; 5. Pop stack variable initialized in step 2.
646
        pop     eax
647
; 6. Restore esi saved in step 1 and return.
648
        pop     esi
649
        ret
650
 
651
; Helper procedure for expand_environment.
652
; Scans the string in esi with length [esp+4]
653
; until '%' is found or line ended.
654
find_percent:
655
        mov     eax, esi
656
        cmp     dword [esp+4], 0
657
        jz      .nothing
658
.scan:
659
        cmp     byte [eax+ebx], '%'
660
        jz      .nothing
661
        inc     eax
662
        dec     dword [esp+4]
663
        jnz     .scan
664
.nothing:
665
        ret
666
 
667
; Helper procedure for copy_{name,asciiz}_escaped.
668
; Allocates space and writes one character, possibly escaped.
669
copy_char_escaped:
670
        cmp     al, ' '
671
        jnz     .noescape
672
        stdcall alloc_in_buf, 1
673
        mov     byte [edi+ebx], '\'
674
        inc     edi
675
.noescape:
676
        stdcall alloc_in_buf, 1
677
        mov     al, [esi+ebx]
678
        inc     esi
679
        cmp     al, '\'
680
        jnz     @f
681
        mov     al, '/'
682
@@:
683
        mov     [edi+ebx], al
684
        inc     edi
685
        ret
686
 
687
; Helper procedure for ensuring that there is at least [esp+4]
688
; free bytes in the buffer.
689
alloc_in_buf:
690
        mov     eax, [esp+4]
691
        sub     [start.free], eax
692
        jb      .need_realloc
693
        ret     4
694
.need_realloc:
695
        mov     eax, [start.allocated]
696
        add     eax, eax
697
        push    ecx edx
698
        call    realloc
699
        pop     edx ecx
700
        cmp     [start.free], 0
701
        jl      .need_realloc
702
        mov     ebx, [start.buf]
703
        ret     4
704
 
705
badfile:
706
        mov     esi, badfile_string
707
        call    sayerr
708
        mov     al, 1
709
        call    exit
710
 
711
information:
712
        mov     esi, information_string
713
        call    sayerr
714
        mov     al, 2
715
        call    exit
716
 
717
nomemory:
718
        mov     esi, nomemory_string
719
        call    sayerr
720
        mov     al, 3
721
        call    exit
722
 
723
in_openerr:
724
        mov     esi, in_openerr_string
725
        jmp     in_err
726
readerr:
727
        mov     esi, readerr_string
728
in_err:
729
        call    sayerr
730
        mov     al, 4
731
        call    exit
732
 
733
out_openerr:
734
        mov     esi, out_openerr_string
735
        jmp     out_err
736
writeerr:
737
        mov     esi, writeerr_string
738
out_err:
739
        call    sayerr
740
        mov     al, 5
741
        call    exit
742
 
743
; Platform-specific procedures.
744
match =WINDOWS,OS { include 'windows_sys.inc' }
745
match =LINUX,OS { include 'linux_sys.inc' }
746
 
747
; Data
748
macro string a, [b] {
749
common
750
        db      a ## _end - a
751
a       db      b
752
a ## _end:
753
}
754
 
755
string information_string, 'Usage: fasmdep [-e] [ []]',10
756
string badfile_string, 'Not .fas file',10
757
string nomemory_string, 'No memory',10
758
string in_openerr_string, 'Cannot open input file',10
759
string readerr_string, 'Read error',10
760
string out_openerr_string, 'Cannot create output file',10
761
string writeerr_string, 'Write error',10
762
 
763
include_variable        db      'INCLUDE',0
764
TokenOn         db      2,'on'
765
TokenFrom       db      4,'from'