; copy (the cp command in Unix/Linux Systems)
; here, we will impliment the "cp" command
; syntax:
; ./copy src dest
; Compile with: nasm -f elf copy.asm
; Link with (64 bit systems require elf_i386 option): ld -m elf_i386 copy.o -o copy
;

; include external files
%include 'functions.asm' ; using the functions file from the tutorial

; section for define statements
SECTION .data
usage db 'Usage: ./copy src dst', 0Ah ; storing a usage statement
                                      ; note that 0Ah is 10 in decimal
                                      ; 10 is the ASCII number for newline character
; section for variables
; resb means "reserve number of bytes"
SECTION .bss
src     resb 8              ; buffer for file descriptor of source file
dst     resb 8              ; buffer for file descriptor of destination file
sz      resb 16             ; reserving 16 bytes to store integer for file size
buffer  resb 10000          ; reserving 10000 bytes to store the contents of a file

; our main program is below
SECTION .text
global _start

; main function
_start:


; deal with command line arguments here
; argc is stored in the ecx register
; argv is stored as a stack in the eax register
; recall that cp takes two arguments, so argc will be 3,
args:
    pop ecx         ; pop ecx to get argc off of the stack
    pop eax         ; pop eax to get argv[0] (the filename), off of the stack
    cmp ecx, 3h     ; checking if argc is 3 (number of args needed)
    jne printUsage  ; if above is false, go to printUsage, else continue below
                    ; "jne" - jump if not equal


    
; open the source file for reading 
opensrc:
    pop eax         ; pop eax to get argv[1] off the stack, this has our filename
    mov ebx, eax    ; open expects the filename to be in ebx,
    mov eax, 5      ; open expects the opcode for open to be in eax,
    mov ecx, 0      ; open expects the mode (read only is 0) to be in ecx
    int 80h         ; call the kernel to invoke the system call

    mov [src], eax  ; open returns a file descriptor in eax
                    ; move it to the src variable we declared above

; read the source file into a buffer
readsrc:
    mov eax, 3       ; move opcode for read into eax
    mov ebx, [src]   ; file descriptor for source goes to ebx
    mov ecx, buffer  ; buffer goes to ecx
    mov edx, 10000   ; number of bytes read goes to edx
    int 80h          ; now call the kernel

                     ; read returns number of bytes read,
    mov [sz], eax    ; store this value in sz, so we can use this later


; create the destination file 
createdst:
    pop eax ; now pop eax to get the destination file

    ; here we need to invoke the "creat" system call first
    ; creat expects 2 arguments, file permissions in ecx, and filename in ebx
    mov ecx, 0644o ; set file permissions to 0644o
    mov ebx, eax   ; move filename currently in eax to ebx
    mov eax, 8     ; opcode for creat goes in eax
    int 80h        ; call the kernel

    mov [dst], eax ; creat returns a file descriptor in eax
                   ; store that in dst, so we can use it to write the buffer to the new file

; write the buffer into the destination file
writedst:
    mov eax, 4      ; opcode for write goes to eax
    mov ebx, [dst]  ; file descriptor for destination goes to ebx
    mov ecx, buffer ; buffer goes to ecx
    mov edx, [sz]   ; number of bytes read earlier (stored in sz), goes to edx
    int 80h         ; then call the kernel


; close the source file
closesrc:
   mov eax, 6       ; opcode for close goes in eax
   mov ebx, [src]   ; file descriptor for src goes in ebx
   int 80h          ; now call the kernel

; close the destination file
closedst:
   mov eax, 6       ; opcode for close goes in eax
   mov ebx, [dst]   ; file descriptor for src goes in ebx
   int 80h          ; now call the kernel

   jmp done
   
; print a usage statement
printUsage:
    mov     eax, usage  ; move usage statement to eax
    call    sprint      ; call sprint (external function in functions.asm)
    jmp     done        ; go to section labeled "done"

; exit the program
done:
    call quit

