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