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