syslinux/core/getc.inc
<<
>>
Prefs
   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
  22MAX_GETC_LG2    equ 4                   ; Max number of file nesting
  23MAX_GETC        equ (1 << MAX_GETC_LG2)
  24bytes_per_getc_lg2      equ 16-MAX_GETC_LG2
  25bytes_per_getc          equ (1 << bytes_per_getc_lg2)
  26MAX_UNGET       equ 9                   ; Max bytes that can be pushed back
  27
  28                struc getc_file
  29gc_file         resw 1                  ; File pointer
  30gc_bufbytes     resw 1                  ; Bytes left in buffer
  31gc_bufdata      resw 1                  ; Pointer to data in buffer
  32gc_unget_cnt    resb 1                  ; Character pushed back count
  33gc_unget_buf    resb MAX_UNGET          ; Character pushed back buffer
  34                endstruc
  35getc_file_lg2   equ 4                   ; Size of getc_file as a power of 2
  36
  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
  42
  43;
  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.
  48;
  49;               All routines assume CS == DS.
  50;
  51;               open:   Input:  mangled filename in DS:DI
  52;                       Output: ZF set on file not found or zero length
  53;
  54;               openfd: Input:  file handle in SI, file size in EAX
  55;                       Output: ZF set on getc stack overflow
  56;
  57;               getc:   Output: CF set on end of file
  58;                               Character loaded in AL
  59;
  60;               close:  Output: CF set if nothing open
  61;
  62                global core_open
  63core_open:
  64                pm_call pm_searchdir
  65                jz openfd.ret
  66openfd:
  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                xor ax,ax
  77                mov [bx+gc_bufbytes],ax         ; Buffer empty
  78                mov [bx+gc_unget_cnt],al        ; ungetc buffer empty
  79
  80                inc ax                  ; ZF <- 0
  81                pop bx
  82.ret:           ret
  83
  84.stack_full:
  85                pm_call pm_close_file
  86                xor ax,ax               ; ZF <- 1
  87                pop bx
  88                ret
  89                
  90getc:
  91                push bx
  92                push si
  93                push di
  94                push es
  95
  96                mov di,[CurrentGetC]
  97                movzx bx,byte [di+gc_unget_cnt]
  98                and bx,bx
  99                jnz .have_unget
 100
 101                mov si,real_mode_seg    ; Borrow the real_mode_seg
 102                mov es,si
 103
 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
 124
 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
 131
 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
 145
 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
 154
 155;
 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...
 158;
 159; On return, CX and DI are adjusted by the number of bytes actually read.
 160;
 161readc:
 162                push ax
 163.loop:
 164                call getc
 165                jc .out
 166                stosb
 167                loop .loop
 168.out:
 169                pop ax
 170                ret
 171
 172;
 173; close: close the top of the getc stack
 174;
 175close:
 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
 186
 187;
 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.
 191;
 192ungetc:
 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
 203
 204;
 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.
 208;
 209;               Otherwise AL = first character after whitespace
 210;
 211skipspace:
 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
 226
 227;
 228; getint:       Load an integer from the getc file.
 229;               Return CF if error; otherwise return integer in EBX
 230;
 231getint:
 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
 246;
 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
 251;
 252;               Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+[KMG]
 253;
 254parseint:
 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
 323
 324                section .bss16
 325                alignb 4
 326NumBuf          resb 15                 ; Buffer to load number
 327NumBufEnd       resb 1                  ; Last byte in NumBuf
 328
 329GetCStack       resb getc_file_size*MAX_GETC
 330.end            equ $
 331
 332                section .data16
 333CurrentGetC     dw GetCStack.end        ; GetCStack empty
 334
 335;
 336; unhexchar:    Convert a hexadecimal digit in AL to the equivalent number;
 337;               return CF=1 if not a hex digit
 338;
 339                section .text16
 340unhexchar:
 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
 356
 357;
 358;
 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.
 365;
 366getline:
 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
 402
 403;
 404; parseint_esdi:
 405;               Same as parseint, but takes the input in ES:DI
 406;
 407parseint_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
 416
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.