Merge commit 'origin/nolen' into gpxe-support
[syslinux.git] / getc.inc
blobb36115cadb54a70e35a16d52c5388b2d6be706b9
1 ;; -----------------------------------------------------------------------
2 ;;
3 ;;   Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
4 ;;
5 ;;   This program is free software; you can redistribute it and/or modify
6 ;;   it under the terms of the GNU General Public License as published by
7 ;;   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 ;;   Boston MA 02111-1307, USA; either version 2 of the License, or
9 ;;   (at your option) any later version; incorporated herein by reference.
11 ;; -----------------------------------------------------------------------
14 ;; getc.inc
16 ;; Simple file handling library (open, getc, ungetc)
18 ;; WARNING: This interface uses the real_mode_seg/comboot_seg.
21 MAX_GETC_LG2    equ 4                   ; Max number of file nesting
22 MAX_GETC        equ (1 << MAX_GETC_LG2)
23 bytes_per_getc_lg2      equ 16-MAX_GETC_LG2
24 bytes_per_getc          equ (1 << bytes_per_getc_lg2)
25 secs_per_getc   equ bytes_per_getc/SECTOR_SIZE
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 open:
63                 call searchdir
64                 jz openfd.ret
65 openfd:
66                 push bx
68                 mov bx,[CurrentGetC]
69                 sub bx,getc_file_size
70                 cmp bx,GetCStack
71                 jb .stack_full          ; Excessive nesting
72                 mov [CurrentGetC],bx
74                 mov [bx+gc_file],si     ; File pointer
75                 xor ax,ax
76                 mov [bx+gc_bufbytes],ax         ; Buffer empty
77                 mov [bx+gc_unget_cnt],al        ; ungetc buffer empty
79                 inc ax                  ; ZF <- 0
80                 pop bx
81 .ret:           ret
83 .stack_full:
84                 call close_file
85                 xor ax,ax               ; ZF <- 1
86                 pop bx
87                 ret
89 getc:
90                 push bx
91                 push si
92                 push di
93                 push es
95                 mov di,[CurrentGetC]
96                 movzx bx,byte [di+gc_unget_cnt]
97                 and bx,bx
98                 jnz .have_unget
100                 mov si,real_mode_seg    ; Borrow the real_mode_seg
101                 mov es,si
103 .got_data:
104                 sub word [di+gc_bufbytes],1
105                 jc .get_data            ; Was it zero already?
106                 mov si,[di+gc_bufdata]
107                 mov al,[es:si]
108                 inc si
109                 mov [di+gc_bufdata],si
110 .done:
111                 clc
112 .ret:
113                 pop es
114                 pop di
115                 pop si
116                 pop bx
117                 ret
118 .have_unget:
119                 dec bx
120                 mov al,[di+bx+gc_unget_buf]
121                 mov [di+gc_unget_cnt],bl
122                 jmp .done
124 .get_data:
125                 pushad
126                 ; Compute start of buffer
127                 mov bx,di
128                 sub bx,GetCStack
129                 shl bx,bytes_per_getc_lg2-getc_file_lg2
131                 mov [di+gc_bufdata],bx
132                 mov si,[di+gc_file]
133                 and si,si
134                 mov [di+gc_bufbytes],si ; In case SI == 0
135                 jz .empty
136                 mov cx,bytes_per_getc >> SECTOR_SHIFT
137                 call getfssec
138                 mov [di+gc_bufbytes],cx
139                 mov [di+gc_file],si
140                 jcxz .empty
141                 popad
142                 TRACER 'd'
143                 jmp .got_data
145 .empty:
146                 TRACER 'e'
147                 ; [di+gc_bufbytes] is zero already, thus we will continue
148                 ; to get EOF on any further attempts to read the file.
149                 popad
150                 xor al,al               ; Return a predictable zero
151                 stc
152                 jmp .ret
154 close:
155                 push bx
156                 push si
157                 mov bx,[CurrentGetC]
158                 mov si,[bx+gc_file]
159                 call close_file
160                 add bx,getc_file_size
161                 mov [CurrentGetC],bx
162                 pop si
163                 pop bx
164                 ret
167 ; ungetc:       Push a character (in AL) back into the getc buffer
168 ;               Note: if more than MAX_UNGET bytes are pushed back, all
169 ;               hell will break loose.
171 ungetc:
172                 push di
173                 push bx
174                 mov di,[CurrentGetC]
175                 movzx bx,[di+gc_unget_cnt]
176                 mov [bx+di+gc_unget_buf],al
177                 inc bx
178                 mov [di+gc_unget_cnt],bl
179                 pop bx
180                 pop di
181                 ret
184 ; skipspace:    Skip leading whitespace using "getc".  If we hit end-of-line
185 ;               or end-of-file, return with carry set; ZF = true of EOF
186 ;               ZF = false for EOLN; otherwise CF = ZF = 0.
188 ;               Otherwise AL = first character after whitespace
190 skipspace:
191 .loop:          call getc
192                 jc .eof
193                 cmp al,1Ah                      ; DOS EOF
194                 je .eof
195                 cmp al,0Ah
196                 je .eoln
197                 cmp al,' '
198                 jbe .loop
199                 ret                             ; CF = ZF = 0
200 .eof:           cmp al,al                       ; Set ZF
201                 stc                             ; Set CF
202                 ret
203 .eoln:          add al,0FFh                     ; Set CF, clear ZF
204                 ret
207 ; getint:       Load an integer from the getc file.
208 ;               Return CF if error; otherwise return integer in EBX
210 getint:
211                 mov di,NumBuf
212 .getnum:        cmp di,NumBufEnd        ; Last byte in NumBuf
213                 jae .loaded
214                 push di
215                 call getc
216                 pop di
217                 jc .loaded
218                 stosb
219                 cmp al,'-'
220                 jnb .getnum
221                 call ungetc             ; Unget non-numeric
222 .loaded:        mov byte [di],0
223                 mov si,NumBuf
224                 ; Fall through to parseint
227 ; parseint:     Convert an integer to a number in EBX
228 ;               Get characters from string in DS:SI
229 ;               Return CF on error
230 ;               DS:SI points to first character after number
232 ;               Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+[KMG]
234 parseint:
235                 push eax
236                 push ecx
237                 push bp
238                 xor eax,eax             ; Current digit (keep eax == al)
239                 mov ebx,eax             ; Accumulator
240                 mov ecx,ebx             ; Base
241                 xor bp,bp               ; Used for negative flag
242 .begin:         lodsb
243                 cmp al,'-'
244                 jne .not_minus
245                 xor bp,1                ; Set unary minus flag
246                 jmp short .begin
247 .not_minus:
248                 cmp al,'0'
249                 jb .err
250                 je .octhex
251                 cmp al,'9'
252                 ja .err
253                 mov cl,10               ; Base = decimal
254                 jmp short .foundbase
255 .octhex:
256                 lodsb
257                 cmp al,'0'
258                 jb .km          ; Value is zero
259                 or al,20h               ; Downcase
260                 cmp al,'x'
261                 je .ishex
262                 cmp al,'7'
263                 ja .err
264                 mov cl,8                ; Base = octal
265                 jmp short .foundbase
266 .ishex:
267                 mov al,'0'              ; No numeric value accrued yet
268                 mov cl,16               ; Base = hex
269 .foundbase:
270                 call unhexchar
271                 jc .km                ; Not a (hex) digit
272                 cmp al,cl
273                 jae .km                 ; Invalid for base
274                 imul ebx,ecx            ; Multiply accumulated by base
275                 add ebx,eax             ; Add current digit
276                 lodsb
277                 jmp short .foundbase
278 .km:
279                 dec si                  ; Back up to last non-numeric
280                 lodsb
281                 or al,20h
282                 cmp al,'k'
283                 je .isk
284                 cmp al,'m'
285                 je .ism
286                 cmp al,'g'
287                 je .isg
288                 dec si                  ; Back up
289 .fini:          and bp,bp
290                 jz .ret         ; CF=0!
291                 neg ebx                 ; Value was negative
292 .done:          clc
293 .ret:           pop bp
294                 pop ecx
295                 pop eax
296                 ret
297 .err:           stc
298                 jmp short .ret
299 .isg:           shl ebx,10              ; * 2^30
300 .ism:           shl ebx,10              ; * 2^20
301 .isk:           shl ebx,10              ; * 2^10
302                 jmp .fini
304                 section .bss1
305                 alignb 4
306 NumBuf          resb 15                 ; Buffer to load number
307 NumBufEnd       resb 1                  ; Last byte in NumBuf
309 GetCStack       resb getc_file_size*MAX_GETC
310 .end            equ $
312                 section .data
313 CurrentGetC     dw GetCStack.end        ; GetCStack empty
316 ; unhexchar:    Convert a hexadecimal digit in AL to the equivalent number;
317 ;               return CF=1 if not a hex digit
319                 section .text
320 unhexchar:
321                 cmp al,'0'
322                 jb .ret                 ; If failure, CF == 1 already
323                 cmp al,'9'
324                 ja .notdigit
325                 sub al,'0'              ; CF <- 0
326                 ret
327 .notdigit:      or al,20h               ; upper case -> lower case
328                 cmp al,'a'
329                 jb .ret                 ; If failure, CF == 1 already
330                 cmp al,'f'
331                 ja .err
332                 sub al,'a'-10           ; CF <- 0
333                 ret
334 .err:           stc
335 .ret:           ret
339 ; getline:      Get a command line, converting control characters to spaces
340 ;               and collapsing streches to one; a space is appended to the
341 ;               end of the string, unless the line is empty.
342 ;               The line is terminated by ^J, ^Z or EOF and is written
343 ;               to ES:DI.  On return, DI points to first char after string.
344 ;               CF is set if we hit EOF.
346 getline:
347                 call skipspace
348                 mov dl,1                ; Empty line -> empty string.
349                 jz .eof               ; eof
350                 jc .eoln              ; eoln
351                 call ungetc
352 .fillloop:      push dx
353                 push di
354                 call getc
355                 pop di
356                 pop dx
357                 jc .ret         ; CF set!
358                 cmp al,' '
359                 jna .ctrl
360                 xor dx,dx
361 .store:         stosb
362                 jmp short .fillloop
363 .ctrl:          cmp al,10
364                 je .ret         ; CF clear!
365                 cmp al,26
366                 je .eof
367                 and dl,dl
368                 jnz .fillloop           ; Ignore multiple spaces
369                 mov al,' '              ; Ctrl -> space
370                 inc dx
371                 jmp short .store
372 .eoln:          clc                     ; End of line is not end of file
373                 jmp short .ret
374 .eof:           stc
375 .ret:           pushf                   ; We want the last char to be space!
376                 and dl,dl
377                 jnz .xret
378                 mov al,' '
379                 stosb
380 .xret:          popf
381                 ret