; getting the size of a file in bytes
; 32 bit NASM
; Compile with: nasm -f elf filesize.asm
; Link with (64 bit systems require elf_i386 option): ld -m elf_i386 filesize.o -o filesize

; including an external file with some functions we can use
; this file was from the tutorial at asmtutor.com
%include        'functions.asm'

;section for define statements
SECTION .data
usage db 'Usage: ./mycat file', 0Ah ; storing a usage statement
                                    ; note that 0Ah is 10 in decimal
                                    ; 10 is the ASCII number for newline character

; we define our variables in this section only
; resb means reserve this number of bytes
SECTION .bss
fd      resb 4              ; reserving 4 bytes of memory to store a descriptor
buffer  resb 10000          ; reserving bytes to store the contents of a file



; next three lines is like "int main" in C
SECTION .text
global  _start  ;directive section

_start:

; dealing with command line arguments
; argc - stored in ecx register
; argv - all args are stored in a stack in eax register
args:
    pop     ecx         ; getting the value of argc by popping it off the stack
    pop     eax         ; getting argv[0]
    dec     ecx         ; decreasing value inside ecx by 1
    cmp     ecx, 0h     ; checking if argc is now 0
    jz      printUsage  ; if above is true, we jump to section labeled "print usage"
                        ; otherwise we continue below

; opening the file for reading
; here we will invoke the "open" systemcall
; to do this we look up the Linux opcode table for 32 bit assembly
; open uses opcode 5, table also details what gets stored where
; What gets stored where: eax: 5 - the opcode for open
;                         ebx: filename
;                         ecx: flags: 0 means read only,
;                         edx: (optional) mode - setting permissions 
openfile:
    pop     eax             ; we still have argv[1] in eax stack, we need to pop it off first

    mov     ebx, eax        ; open will look for a filename in ebx, so we must move it there
    mov     ecx, 0          ; flag for readonly access mode (O_RDONLY) in ecx
    mov     eax, 5          ; invoke SYS_OPEN (kernel opcode 5) by putting 5 into eax
    int     80h             ; call the kernel (this runs the function)

    mov     [fd], eax       ; open will return a file descriptor that is stored in eax
                            ; we need to store this somewhere so we create a variable fd
                            ; we define what fd is above in SECTION .bss, and put square 
                            ; brackets around it works like a pointer in C


; reading the file into a buffer
; now we invoke the "read" systemcall
; what gets stored where:  eax: 3 - the opcode for read
;                          ebx: file descriptor (currently in [fd])
;                          ecx: the buffer we will read into (define this up in SECTION .bss)
;                          edx: the (maximum) number of bytes we will read

readfile:
     mov     edx, 100000      ; maximum number of bytes to read - one for each letter of the file contents
     mov     ecx, buffer      ; move the buffer into ecx
     mov     ebx, [fd]        ; move the opened file descriptor into ebx (don't forget the brackets)
     mov     eax, 3           ; invoke SYS_READ (kernel opcode 3)
     int     80h              ; call the kernel

     ; readfile will return the number of bytes read into eax, 
     ; here we want to print this value out, so we will use the 
     ; iprintLF function found in functions.asm

     call iprintLF

; close open file
; now we invoke the "close" systemcall
; what gets stored where: eax: 6 - the opcode for close
;                         ebx: the file descriptor we're closing
close:
     mov     ebx, [fd]           ; moving file descriptor to ebx
     mov     eax, 6              ; invoke SYS_CLOSE (kernel opcode 6)
     int     80h                 ; call the kernel 

     jmp     done                 ; we don't want to print a usage statement, so we'll go directly to "done"


;if no argument was provided, we print a usage statement then go to done
printUsage:
    mov     eax, usage  ; move usage statement to eax
    call    sprint      ; using external function in functions.asm
    jmp     done        ; go to section labeled "done"

;exit the program
done:
    call    quit    ; external function that cleanly exits the program



