Add 32-bit versions of open file/close file
[profile/ivi/syslinux.git] / core / getc.inc
1 ;; -----------------------------------------------------------------------
2 ;;
3 ;;   Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
4 ;;   Copyright 2009 Intel Corporation; author: H. Peter Anvin
5 ;;
6 ;;   This program is free software; you can redistribute it and/or modify
7 ;;   it under the terms of the GNU General Public License as published by
8 ;;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
9 ;;   Boston MA 02111-1307, USA; either version 2 of the License, or
10 ;;   (at your option) any later version; incorporated herein by reference.
11 ;;
12 ;; -----------------------------------------------------------------------
13
14 ;;
15 ;; getc.inc
16 ;;
17 ;; Simple file handling library (open, getc, ungetc)
18 ;;
19 ;; WARNING: This interface uses the real_mode_seg/comboot_seg.
20 ;;
21
22 MAX_GETC_LG2    equ 4                   ; Max number of file nesting
23 MAX_GETC        equ (1 << MAX_GETC_LG2)
24 bytes_per_getc_lg2      equ 16-MAX_GETC_LG2
25 bytes_per_getc          equ (1 << bytes_per_getc_lg2)
26 secs_per_getc   equ bytes_per_getc/SECTOR_SIZE
27 MAX_UNGET       equ 9                   ; Max bytes that can be pushed back
28
29                 struc getc_file
30 gc_file         resw 1                  ; File pointer
31 gc_bufbytes     resw 1                  ; Bytes left in buffer
32 gc_bufdata      resw 1                  ; Pointer to data in buffer
33 gc_unget_cnt    resb 1                  ; Character pushed back count
34 gc_unget_buf    resb MAX_UNGET          ; Character pushed back buffer
35                 endstruc
36 getc_file_lg2   equ 4                   ; Size of getc_file as a power of 2
37
38 %ifndef DEPEND
39 %if (getc_file_size != (1 << getc_file_lg2))
40 %error "getc_file_size != (1 << getc_file_lg2)"
41 %endif
42 %endif
43
44 ;
45 ; open,getc:    Load a file a character at a time for parsing in a manner
46 ;               similar to the C library getc routine.
47 ;               Up to MAX_GETC files can be open at the same time,
48 ;               they are accessed in a stack-like fashion.
49 ;
50 ;               All routines assume CS == DS.
51 ;
52 ;               open:   Input:  mangled filename in DS:DI
53 ;                       Output: ZF set on file not found or zero length
54 ;
55 ;               openfd: Input:  file handle in SI, file size in EAX
56 ;                       Output: ZF set on getc stack overflow
57 ;
58 ;               getc:   Output: CF set on end of file
59 ;                               Character loaded in AL
60 ;
61 ;               close:  Output: CF set if nothing open
62 ;
63                 global core_open
64 core_open:
65                 pm_call pm_searchdir
66                 jz openfd.ret
67 openfd:
68                 push bx
69
70                 mov bx,[CurrentGetC]
71                 sub bx,getc_file_size
72                 cmp bx,GetCStack
73                 jb .stack_full          ; Excessive nesting
74                 mov [CurrentGetC],bx
75
76                 mov [bx+gc_file],si     ; File pointer
77                 xor ax,ax
78                 mov [bx+gc_bufbytes],ax         ; Buffer empty
79                 mov [bx+gc_unget_cnt],al        ; ungetc buffer empty
80
81                 inc ax                  ; ZF <- 0
82                 pop bx
83 .ret:           ret
84
85 .stack_full:
86                 pm_call pm_close_file
87                 xor ax,ax               ; ZF <- 1
88                 pop bx
89                 ret
90                 
91 getc:
92                 push bx
93                 push si
94                 push di
95                 push es
96
97                 mov di,[CurrentGetC]
98                 movzx bx,byte [di+gc_unget_cnt]
99                 and bx,bx
100                 jnz .have_unget
101
102                 mov si,real_mode_seg    ; Borrow the real_mode_seg
103                 mov es,si
104
105 .got_data:
106                 sub word [di+gc_bufbytes],1
107                 jc .get_data            ; Was it zero already?
108                 mov si,[di+gc_bufdata]
109                 mov al,[es:si]
110                 inc si
111                 mov [di+gc_bufdata],si
112 .done:
113                 clc
114 .ret:
115                 pop es
116                 pop di
117                 pop si
118                 pop bx
119                 ret
120 .have_unget:
121                 dec bx
122                 mov al,[di+bx+gc_unget_buf]
123                 mov [di+gc_unget_cnt],bl
124                 jmp .done
125
126 .get_data:
127                 pushad
128                 ; Compute start of buffer
129                 mov bx,di
130                 sub bx,GetCStack
131                 shl bx,bytes_per_getc_lg2-getc_file_lg2
132
133                 mov [di+gc_bufdata],bx
134                 mov si,[di+gc_file]
135                 and si,si
136                 mov [di+gc_bufbytes],si ; In case SI == 0
137                 jz .empty
138                 mov cx,bytes_per_getc >> SECTOR_SHIFT
139                 pm_call getfssec
140                 mov [di+gc_bufbytes],cx
141                 mov [di+gc_file],si
142                 jcxz .empty
143                 popad
144                 TRACER 'd'
145                 jmp .got_data
146
147 .empty:
148                 TRACER 'e'
149                 ; [di+gc_bufbytes] is zero already, thus we will continue
150                 ; to get EOF on any further attempts to read the file.
151                 popad
152                 xor al,al               ; Return a predictable zero
153                 stc
154                 jmp .ret
155
156 ;
157 ; This is similar to getc, except that we read up to CX bytes and
158 ; store them in ES:DI.  Eventually this could get optimized...
159 ;
160 ; On return, CX and DI are adjusted by the number of bytes actually read.
161 ;
162 readc:
163                 push ax
164 .loop:
165                 call getc
166                 jc .out
167                 stosb
168                 loop .loop
169 .out:
170                 pop ax
171                 ret
172
173 ;
174 ; close: close the top of the getc stack
175 ;
176 close:
177                 push bx
178                 push si
179                 mov bx,[CurrentGetC]
180                 mov si,[bx+gc_file]
181                 pm_call pm_close_file
182                 add bx,getc_file_size
183                 mov [CurrentGetC],bx
184                 pop si
185                 pop bx
186                 ret
187
188 ;
189 ; ungetc:       Push a character (in AL) back into the getc buffer
190 ;               Note: if more than MAX_UNGET bytes are pushed back, all
191 ;               hell will break loose.
192 ;
193 ungetc:
194                 push di
195                 push bx
196                 mov di,[CurrentGetC]
197                 movzx bx,[di+gc_unget_cnt]
198                 mov [bx+di+gc_unget_buf],al
199                 inc bx
200                 mov [di+gc_unget_cnt],bl
201                 pop bx
202                 pop di
203                 ret
204
205 ;
206 ; skipspace:    Skip leading whitespace using "getc".  If we hit end-of-line
207 ;               or end-of-file, return with carry set; ZF = true of EOF
208 ;               ZF = false for EOLN; otherwise CF = ZF = 0.
209 ;
210 ;               Otherwise AL = first character after whitespace
211 ;
212 skipspace:
213 .loop:          call getc
214                 jc .eof
215                 cmp al,1Ah                      ; DOS EOF
216                 je .eof
217                 cmp al,0Ah
218                 je .eoln
219                 cmp al,' '
220                 jbe .loop
221                 ret                             ; CF = ZF = 0
222 .eof:           cmp al,al                       ; Set ZF
223                 stc                             ; Set CF
224                 ret
225 .eoln:          add al,0FFh                     ; Set CF, clear ZF
226                 ret
227
228 ;
229 ; getint:       Load an integer from the getc file.
230 ;               Return CF if error; otherwise return integer in EBX
231 ;
232 getint:
233                 mov di,NumBuf
234 .getnum:        cmp di,NumBufEnd        ; Last byte in NumBuf
235                 jae .loaded
236                 push di
237                 call getc
238                 pop di
239                 jc .loaded
240                 stosb
241                 cmp al,'-'
242                 jnb .getnum
243                 call ungetc             ; Unget non-numeric
244 .loaded:        mov byte [di],0
245                 mov si,NumBuf
246                 ; Fall through to parseint
247 ;
248 ; parseint:     Convert an integer to a number in EBX
249 ;               Get characters from string in DS:SI
250 ;               Return CF on error
251 ;               DS:SI points to first character after number
252 ;
253 ;               Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+[KMG]
254 ;
255 parseint:
256                 push eax
257                 push ecx
258                 push bp
259                 xor eax,eax             ; Current digit (keep eax == al)
260                 mov ebx,eax             ; Accumulator
261                 mov ecx,ebx             ; Base
262                 xor bp,bp               ; Used for negative flag
263 .begin:         lodsb
264                 cmp al,'-'
265                 jne .not_minus
266                 xor bp,1                ; Set unary minus flag
267                 jmp short .begin
268 .not_minus:
269                 cmp al,'0'
270                 jb .err
271                 je .octhex
272                 cmp al,'9'
273                 ja .err
274                 mov cl,10               ; Base = decimal
275                 jmp short .foundbase
276 .octhex:
277                 lodsb
278                 cmp al,'0'
279                 jb .km          ; Value is zero
280                 or al,20h               ; Downcase
281                 cmp al,'x'
282                 je .ishex
283                 cmp al,'7'
284                 ja .err
285                 mov cl,8                ; Base = octal
286                 jmp short .foundbase
287 .ishex:
288                 mov al,'0'              ; No numeric value accrued yet
289                 mov cl,16               ; Base = hex
290 .foundbase:
291                 call unhexchar
292                 jc .km                ; Not a (hex) digit
293                 cmp al,cl
294                 jae .km                 ; Invalid for base
295                 imul ebx,ecx            ; Multiply accumulated by base
296                 add ebx,eax             ; Add current digit
297                 lodsb
298                 jmp short .foundbase
299 .km:
300                 dec si                  ; Back up to last non-numeric
301                 lodsb
302                 or al,20h
303                 cmp al,'k'
304                 je .isk
305                 cmp al,'m'
306                 je .ism
307                 cmp al,'g'
308                 je .isg
309                 dec si                  ; Back up
310 .fini:          and bp,bp
311                 jz .ret         ; CF=0!
312                 neg ebx                 ; Value was negative
313 .done:          clc
314 .ret:           pop bp
315                 pop ecx
316                 pop eax
317                 ret
318 .err:           stc
319                 jmp short .ret
320 .isg:           shl ebx,10              ; * 2^30
321 .ism:           shl ebx,10              ; * 2^20
322 .isk:           shl ebx,10              ; * 2^10
323                 jmp .fini
324
325                 section .bss16
326                 alignb 4
327 NumBuf          resb 15                 ; Buffer to load number
328 NumBufEnd       resb 1                  ; Last byte in NumBuf
329
330 GetCStack       resb getc_file_size*MAX_GETC
331 .end            equ $
332
333                 section .data16
334 CurrentGetC     dw GetCStack.end        ; GetCStack empty
335
336 ;
337 ; unhexchar:    Convert a hexadecimal digit in AL to the equivalent number;
338 ;               return CF=1 if not a hex digit
339 ;
340                 section .text16
341 unhexchar:
342                 cmp al,'0'
343                 jb .ret                 ; If failure, CF == 1 already
344                 cmp al,'9'
345                 ja .notdigit
346                 sub al,'0'              ; CF <- 0
347                 ret
348 .notdigit:      or al,20h               ; upper case -> lower case
349                 cmp al,'a'
350                 jb .ret                 ; If failure, CF == 1 already
351                 cmp al,'f'
352                 ja .err
353                 sub al,'a'-10           ; CF <- 0
354                 ret
355 .err:           stc
356 .ret:           ret
357
358 ;
359 ;
360 ; getline:      Get a command line, converting control characters to spaces
361 ;               and collapsing streches to one; a space is appended to the
362 ;               end of the string, unless the line is empty.
363 ;               The line is terminated by ^J, ^Z or EOF and is written
364 ;               to ES:DI.  On return, DI points to first char after string.
365 ;               CF is set if we hit EOF.
366 ;
367 getline:
368                 call skipspace
369                 mov dl,1                ; Empty line -> empty string.
370                 jz .eof               ; eof
371                 jc .eoln              ; eoln
372                 call ungetc
373 .fillloop:      push dx
374                 push di
375                 call getc
376                 pop di
377                 pop dx
378                 jc .ret         ; CF set!
379                 cmp al,' '
380                 jna .ctrl
381                 xor dx,dx
382 .store:         stosb
383                 jmp short .fillloop
384 .ctrl:          cmp al,10
385                 je .ret         ; CF clear!
386                 cmp al,26
387                 je .eof
388                 and dl,dl
389                 jnz .fillloop           ; Ignore multiple spaces
390                 mov al,' '              ; Ctrl -> space
391                 inc dx
392                 jmp short .store
393 .eoln:          clc                     ; End of line is not end of file
394                 jmp short .ret
395 .eof:           stc
396 .ret:           pushf                   ; We want the last char to be space!
397                 and dl,dl
398                 jnz .xret
399                 mov al,' '
400                 stosb
401 .xret:          popf
402                 ret
403
404 ;
405 ; parseint_esdi:
406 ;               Same as parseint, but takes the input in ES:DI
407 ;
408 parseint_esdi:
409                 push ds
410                 push es
411                 pop ds
412                 xchg si,di
413                 call parseint
414                 xchg si,di
415                 pop ds
416                 ret