assemblyfile-iox86file-handlingtasm

Implementing a task deletion function in Assembly x86 tasm


I'm currently working on an Assembly x86 tasm language program for task management that allows adding and viewing tasks. However, I've been struggling to implement a function to delete a specific task.

.model small
.stack 100h
.data
sir db 80 dup('$') 
m2 db 'Introduceti sirul:$'
m4 db '1. Add task', 13, 10, '$'
m5 db '2. View tasks', 13, 10, '$'
filename db 'tasks.txt',0
handle dw ?
strLength dw ?
t_handle dw ?
newline db 13, 10, '$' ; New line characters
menuChoice db ?
buffer db 2000 dup(0)
.code
    mov ax,@data
    mov ds,ax
    
    mov ah, 9h
    mov dx, offset m4
    int 21h
    
    mov ah, 9h
    mov dx, offset m5
    int 21h
    
    mov ah, 1h
    int 21h
    mov menuChoice, al
    
    cmp menuChoice, '1'
    je add_task
    cmp menuChoice, '2'
    je view_tasks
    cmp menuChoice, '3'
    je delete_aux
    
    jmp end_program

view_tasks:
    ; Opening file for reading
    mov ah, 3Dh 
    mov al, 0 
    mov dx, offset filename 
    int 21h 
    mov handle, ax 

    ; Reading file contents
    mov ah, 3Fh 
    mov bx, handle 
    mov dx, offset sir 
    mov cx, 80 
    int 21h 

    ; Displaying tasks line by line with incrementing numbers
    mov si, offset sir

    display_loop:
        ; Check if end of file or end of buffer
        cmp byte ptr [si], '$'
        je end_display
        ; Print character to screen
        mov ah, 02h 
        mov dl, [si] 
        int 21h 
        ; Move to the next character
        inc si
        jmp display_loop

    end_display:
    ; Close the file
    mov ah, 3Eh ; File close service
    mov bx, handle ; File handle
    int 21h ; File close interrupt

    jmp end_program

delete_aux:
    cmp menuChoice, '3' ; Check if the choice is for delete
    jne view_tasks ; If not, jump to view_tasks
    jmp delete_task ; If yes, jump to delete_task

add_task:
    ; Clearing the buffer
    mov ah, 0Ah
    mov dx, offset sir
    int 21h

    ; Adding a task to the file
    ; Prompting for task input
    mov ah, 9h
    mov dx, offset m2
    int 21h
    
    mov bx,0 
    mov cx,80 
    mov ah,3fh
    mov dx,offset sir
    int 21h

    mov ah, 9h
    mov dx, offset sir
    int 21h

    ; Calculating string length
    mov si, offset sir
    add si, 2
    mov cx, 0 ; Initialize count
    count_length:
        cmp byte ptr [si], '$' 
        je end_count
        inc cx 
        inc si
        jmp count_length 
    
    end_count:
    mov strLength, cx 

    ; Opening file for appending at the end
    mov ah, 3Dh 
    mov al, 2 ;
    mov dx, offset filename
    int 21h 
    mov handle, ax 

    ; Positioning at the end of the file
    mov ah, 42h 
    mov al, 2 
    mov bx, handle 
    mov cx, 0 
    mov dx, 0 
    int 21h 

    ; Writing string to file
    mov ah, 40h
    mov bx, handle 
    mov dx, offset sir 
    mov cx, strLength
    int 21h

; Writing newline to file
    mov ah, 40h 
    mov bx, handle
    mov dx, offset newline 
    mov cx, 2
    int 21h

    ; Closing the file
    mov ah, 3Eh 
    mov bx, handle
    int 21h
   
    jmp view_tasks

delete_task:
    
    jmp view_tasks ; Redirect to view tasks after deletion


end_program:
    mov ah,4Ch
    int 21h
end

I've tried implementing a 'Delete task' option and managed file operations using termination characters 13, 10, '$', but I can't get the hang of it.

delete_task:
    ; Prompt for task number to delete
    mov ah, 9h
    mov dx, offset m_delete_prompt
    int 21h

    ; Read user input for the task number to delete
    mov ah, 1h
    int 21h
    sub al, '0' 
    mov bl, al

    ; Opening the file for reading and writing
    mov ah, 3Dh 
    mov al, 2 
    mov dx, offset filename 
    int 21h
    mov handle, ax 

    ; Reading and deleting the desired task
    mov ah, 3Fh 
    mov bx, handle 
    mov dx, offset buffer 
    mov cx, 2000 
    int 21h

    mov si, offset buffer
    mov di, si

    delete_loop:
        cmp byte ptr [si], '$' 
        je end_delete
        mov al, [si]
        cmp al, 13 
        je check_next_char
        mov [di], al 
        inc di
        inc si
        jmp delete_loop

    check_next_char:
        inc si ; Move to next character (LF)
        mov al, [si]
        cmp al, 10
        je delete_task_found
        mov byte ptr [di], 13 
        inc di
        mov [di], al
        inc di 
        inc si
        jmp delete_loop

    delete_task_found:
        ; Check if it's the desired task to delete
        sub al, '0' 
        cmp al, bl  
        je skip_task   
        jmp copy_task

    skip_task:
        ; Skip the task to delete
        mov al, [si]
        cmp al, 13  
        jne skip_task 
        jmp delete_loop

    copy_task:
        ; Copy the task to keep it
        mov [di], al
        inc di 
        inc si 
        jmp delete_loop

    end_delete:
        ; Truncate the file at the updated position
        mov ah, 40h
        mov bx, handle
        mov dx, offset buffer
        sub di, offset buffer
        int 21h

        ; Close the file
        mov ah, 3Eh 
        mov bx, handle
        int 21h

    jmp view_tasks

; Data Section
m_delete_prompt db 'Enter the task number to delete: $'

For the following tasks:

task1
task2
task3
task4
task5

This is what I got:

task1
task2
task3
task4
task5
task1Útask2Útask3Útask4Útask5Ú                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             ÿÿùtâ

Solution

    1. As I said in comment above, the number of task for deletion should be saved. So push bx does the job. Restore this value by using pop bx before delete_loop:.

    2. This instruction cmp byte ptr [si], '$' at the begining of delete_loop searches for $ but buffer is filled with 0's. So this loop could run forever unless somewhere in memory there is $. So either fill buffer with $ or add variable eotb db '$' after buffer to mark end of the buffer.

    3. What is going on inside delete_loop is this..

      • if byte is 0d go to check_next_char:
      • if byte is 0a go to delete_task_found:
      • al = 0a, so this instruction sub al '0' doesn't substract '0' from '1' - '9' to get proper task number
      • other characters t,a,s,k,1 - 9 are skipped
    4. I can propose this solution...

      • Each record in file looks like this task 1-9 0d 0a

      • First number of the task is at location buffer + 4

      • Next are every 7 bytes:

        buffer + 4 + 7

        buffer + 4 + 7 + 7

        buffer + 4 + 7 + 7 + 7

        buffer + 4 + 7 + 7 + 7 ...

      • If program finds number of the task in file it modifies buffer and writes new data to file else $ means there is no task in file.

    5. I wrote code just for deleting tasks

      .model small
      .stack 100h
      .data
      sir db 80 dup('$') 
      m2 db 'Introduceti sirul:$'
      m4 db '1. Add task', 13, 10, '$'
      m5 db '2. View tasks', 13, 10, '$'
      m6 db '3. Del tasks', 13, 10, '$'   
      
      filename db 'code60t.txt',0
      filesize dw ?
      handle dw ?
      strLength dw ?
      t_handle dw ?
      newline db 13, 10, '$' ; New line characters
      menuChoice db ?
      buffer db 70 dup('$')
      
      m_delete_prompt db 13,10,'Enter the task number to delete: $'
      task_doesnt_exists db 13,10,'This task is not in the file.',13,10,'$'
      del_task db 13,10,'Deleting task number $'  
      
      .code
      start:
      mov ax,@data
      mov ds,ax
      
      mov ah, 9h
      mov dx, offset m4
      int 21h
      
      mov ah, 9h
      mov dx, offset m5
      int 21h
      
      mov ah, 9h
      mov dx, offset m6
      int 21h
      
      mov ah, 1h
      int 21h
      mov menuChoice, al
      
      mov ah, 9h
      mov dx, offset newline
      int 21h
      
      cmp menuChoice, '1'
      je add_task
      cmp menuChoice, '2'
      je view_tasks
      cmp menuChoice, '3'
      je delete_aux
      
      jmp end_program
      
      view_tasks:
      ; Opening file for reading
      mov ah, 3Dh 
      mov al, 2 
      mov dx, offset filename 
      int 21h 
      mov handle, ax 
      
      ; Reading file contents
      mov ah, 3Fh 
      mov bx, handle 
      mov dx, offset sir 
      mov cx, 80 
      int 21h 
      
      ; Displaying tasks line by line with incrementing numbers
      mov si, offset sir
      
      display_loop:
          ; Check if end of file or end of buffer
          cmp byte ptr [si], '$'
          je end_display
          ; Print character to screen
          mov ah, 02h 
          mov dl, [si] 
          int 21h 
          ; Move to the next character
          inc si
          jmp display_loop
      
      end_display:
      ; Close the file
      mov ah, 3Eh ; File close service
      mov bx, handle ; File handle
      int 21h ; File close interrupt
      
      jmp end_program
      
      delete_aux:
      cmp menuChoice, '3' ; Check if the choice is for delete
      jne view_tasks ; If not, jump to view_tasks
      jmp delete_task ; If yes, jump to delete_task
      
      add_task:
      ; Clearing the buffer
      mov ah, 0Ah
      mov dx, offset sir
      int 21h
      
      ; Adding a task to the file
      ; Prompting for task input
      mov ah, 9h
      mov dx, offset m2
      int 21h
      
      mov bx,0 
      mov cx,80 
      mov ah,3fh
      mov dx,offset sir
      int 21h
      
      mov ah, 9h
      mov dx, offset sir
      int 21h
      
      ; Calculating string length
      mov si, offset sir
      add si, 2
      mov cx, 0 ; Initialize count
      count_length:
          cmp byte ptr [si], '$' 
          je end_count
          inc cx 
          inc si
          jmp count_length 
      
      end_count:
      mov strLength, cx 
      
      ; Opening file for appending at the end
      mov ah, 3Dh 
      mov al, 2 ;
      mov dx, offset filename
      int 21h 
      mov handle, ax 
      
      ; Positioning at the end of the file
      mov ah, 42h 
      mov al, 2 
      mov bx, handle 
      mov cx, 0 
      mov dx, 0 
      int 21h 
      
      ; Writing string to file
      mov ah, 40h
      mov bx, handle 
      mov dx, offset sir 
      mov cx, strLength
      int 21h
      
      ; Writing newline to file
      mov ah, 40h 
      mov bx, handle
      mov dx, offset newline 
      mov cx, 2
      int 21h
      
      ; Closing the file
      mov ah, 3Eh 
      mov bx, handle
      int 21h
      
      jmp view_tasks
      
      ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
      
       delete_task: 
      ; Prompt for task number to delete
      mov ah, 9h
      mov dx, offset m_delete_prompt
      int 21h
      
      ; Read user input for the task number to delete
      mov ah, 1h
      int 21h    
      mov bl, al
      
      push bx             ; save the number of the task
      
      ;---- file operations
      
      ; Opening the file for reading and writing
      mov ah, 3Dh 
      mov al, 2 
      mov dx, offset filename 
      int 21h
      mov handle, ax 
      
      ; Reading from file to buffer
      mov ah, 3Fh 
      mov bx, handle 
      mov dx, offset buffer 
      mov cx, 70 
      int 21h
      
      ; calculate file size, this value is used later
      mov ah,42h
      mov al,2
      xor cx,cx
      xor dx,dx
      int 21h
      mov filesize, ax
      
      ; close file, later program uses 3ch because we want to delete old data in file and write modified data
      mov ah, 3eh     
      int 21h
      
      ;---- buffer operations
      
      mov si, offset buffer
      add si, 4       ; first location of the task number
      
      pop bx          ; restore the number of task 
      
      delete_loop:
          cmp byte ptr [si],'$'       ; check if we reached end of buffer
          je no_tasks
          mov al, [si]                ; task number
          cmp al, bl                  ; is this our task?
          je task_found               ; yes
          add si, 7                   ; no, go to next record
          jmp delete_loop             ; try again
      
      task_found:                 
          mov ah, 9h                  ; show some messages
          mov dx, offset del_task
          int 21h
      
          mov ah, 2h
          mov dl, bl      
          int 21h     
      
          mov ah, 9h
          mov dx, offset newline
          int 21h
      
          add si, 3                   ; start of the next record  
          mov di, si
          sub di, 7                   ; start of the record we want to delete
                                      ; do this by moving rest of the tasks up 7 bytes
      
          mov al, 10                  ; we can have max 9 tasks (9 * 7 bytes = 63) + 7 bytes of '$' to clear end of the list
          mov ah, 0
      
          sub bl, 30h
          sub al, bl                   ; calculate how many bytes to copy
          mov bl, 7
          mul bl      
          mov cx, ax          
      
          tasks_move:
              mov al, [si]
              mov [di], al
              inc si
              inc di
              dec cx
              jnz tasks_move
      
          write_to_file:
              mov ah, 3ch         
              mov dx, offset filename
              mov cx, 2           
              int 21h             
      
              ; Writing modified buffer to file
              mov bx, ax
              mov ah, 40h         
              mov dx, offset buffer 
              mov cx, filesize
              sub cx,7
              int 21h     
      
              mov ah, 3eh     
              int 21h
      
      jmp view_tasks
      
      no_tasks:
          mov ah, 9h
          mov dx, offset task_doesnt_exists
          int 21h     
      
      jmp view_tasks
      
      
      end_program:
          mov ah,4Ch
          int 21h
      end start