;finger pointer ; mouse_scr dw 0E1FFh, 0E1FFh, 0E1FFh, 0E1FFh, 0E1FFh ; dw 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; mouse_cur dw 1E00h, 1200h, 1200h, 1200h, 1200h, 13FFh, 1249h ; dw 1249h, 0F249h, 9001h, 9001h, 9001h, 8001h, 8001h, 8001h ; dw 0FFFFh ; black blue green red purple yellow white colour_table db 0,0,0, 0,0,60, 0,60,0, 60,0,0, 60,0,60, 60,60,0, 60,60,60 ; 0 1 2 3 4 5 6 ;get_time CH = hours CL = minutes DH = seconds DL = hundsecs ;num_to_string ;get_string ;string_to_num ;clear_screen ;draw_texel ;copy_screen ;erase_col ;erase_line ;move_shot ;change_colour ;wait_sec wait for 1 second ;wait_hundsec wait for 1/100 of a second ;rain_fall graphic 13h ;clear_line graphic 13h ;clear_buffer clear keyboard buffer ;draw_msg print a string on the 13h graphic screen ;calc_off offset on a graphic screen 13h ;calc_offset finds the offset of X,Y on the graphic screen ;draw_pix place pix of colour on 13h screen ;show_ptr ;hide_ptr ;readkey ;mouse_status returns the position of the mouse on 13h and the buttons ;define_mouse define the mouse cursor ;vline mode 13h ;hline mode 13h ;set_colours mode 13h ;exist checks to see if a file exists ;make_file makes a new empty file ;close_file ;delete_file ;open_file opens a file for read/write access ;read_file ;write_file ;check_for_input checks to see if the user has pressed a key ; or mouse button. If a key was pressed, it clears the buffer ; ;get_param copies the command line paramters to a buffer in the ; data segment ;word_count ;counts the number of words in a string ;letter_count ;counts the number of letters in a string ;clean_up ;clears the keyboard buffer and clears the text screen ;small_wait ;waits for a time in mircoseconds ;hide_cursor makes the cursor disappear ;fill_screen randomly fills the text screen with characters of colour DH ;substr find the position of a sub-string inside a string ;erase_line erase one line of the 13h graphic screen ;pull_blinds clear the 13h graphic screen in a cool way ;save_text save text screen to data segment ;restore_text load text from data segment ;file_get_line reads a line from a DOS format text file. ;upper_case_line makes a line of text all upper case ; Before using memory allocations, read directions VERY CAREFULLY! ; malloc allocated dynamic memory for your program ; free frees allocated memory from your program ; calloc allocates and initilizes dynamic memory ; realloc re-sizes dynamic memory for your program. ; NOTE: you must call realloc at the start of your ; program, BEFORE ANYTHING ELSE as follows ; .code ; mov BX, size_of_exe_in_bytes ; call realloc ; Create_List ; accepts size of data, returns ptr to list struct ; Delete_List ; deltes all nodes in a list and the list ; Create_Node ; accetps ptr to list struct returns ptr to node ; Delete_Node ; deletes node, keeps list intact ; Set_Data ; accepts ptr to node and ptr to new data ; Get_Data ; accepts ptr to node and ptr to data buffer ; Add_Node ; add node to front of list ; Insert_Node ; insert node into middle of list ; Append_Node ; add node to end of list ; Goto_First_Node; move to first node in the list ; Goto_Next_Node ; move to next node in list ; Get_Data_Size ; accepts pointer to list struct and returns size in CX ; Find_Data ; accepts buffer to data and ptr to list, returns node ptr ; mem_cmp ; compare two buffers of memory ; returns the current time ; CH = hours CL = minutes DH = seconds DL = hundsecs get_time proc mov AX, 2C00h int 21h ret get_time endp ; procedure NUM_TO_STRING PROC ;This procedure takes a binary value in AX and converts it to a string ;of characters. ; provided by Bill Power ; REQUIREMENTS: ; DS:BX must contain the offset of the END OF the variable to hold the ; string value to be converted. AX must contain the value to change to a ; string. CX must contain the maximum length of the string. num_to_string proc push CX push BX push SI push dx ; mov si, 10 ; put the divisor [radix] in SI ; convert_loop: XOR DX, DX ; clear the DX registor div SI ; divide DX:AX by SI (10) add DL, 48 ; convert remander in DL to ASCII code mov DS:[BX], DL ; save the ASCII code to byte_string dec BX ; move to the next place in byte_string cmp AX, 0 JE all_done ; If AX = 0 then jump to label all_done loop convert_loop ; all_done: ; pop dx pop SI pop BX pop CX ; restore the registors to their orginal values ret num_to_string endp ; end of the procedure num_to_string ; Procedure get_string, provided by Bill Power ;This procedure accepts a string of characters from the user, ending ; with the ENTER (13) key. ;Requirements: ; Point DS:BX to point to the start of the string. ; CX contains the maximum string length. get_string proc mov DX, CX xor AL, AL read_loop: mov AH, 01h ; call int 21/01h int 21h ;gets a character from the keyboard (readkey) CMP AL, 13 ; checks to see if the user pressed ENTER JE done ; if the user presses ENTER, jump to DONE CMP AL, 8 ; if backspace is pressed JNE okay CMP CX, DX JG stay dec BX mov AL, 32 mov [BX], AL PUSH BX PUSH CX mov AX, 0A20h xor BX, BX mov CX, 1 int 10h POP CX POP BX stay: inc CX inc CX JMP reader okay: mov [BX], AL ; place the ASCCI code in AL in the VAR filename inc BX ; move the VAR pointer ahead one reader: loop read_loop ; do the loop again until CX = 0 or ENTER is hit ; done: ret ; return to the main program get_string endp ; end of procedure ;string_to_num procedure ;This proc takes a string of characters and converts them to a numeric ;value. The answer is returned in AX. CX contains the number of ;characters in the string. ;REQUIREMENTS: ; DS:SI must point to the string to be converted. string_to_num proc xor DX, DX xor AX, AX mov DI, 48 mov BL, 10 ;move the radix (base) into BX mov AL, DS:[SI] ;place the first value in AX cmp ax, 48 ;if the first character is less than "0" then end JB done_read sub ax, 48 ;change the ascii code to a numeric value CMP CX, 1 JE done_proc start_loop: CMP CX, 1 JE done_proc inc SI ;move to the next character mov DL, DS:[SI] cmp DX, DI ;if the next character is less than 0 then done JB done_proc sub DX, 48 ; convert the character to a numeric value MUL BL ; AX = AX * 10 add AX, DX ; add DI to AX loop start_loop JMP done_proc done_read: xor dx, dx xor ax, ax ;set the returning answer to 0 done_proc: ret string_to_num endp ;clear_screen procedure ;This procedure will erase the entire text screen clear_screen proc mov ah, 06h ;function 6 xor al, al ; al = 0 will clear the screen mov bh, 07h ;gray text on black background xor CX, CX ;start at line 0, collum 0 mov DH, 24 ;the last line to erase mov DL, 79 ;the last collum to erase int 10h ret clear_screen endp ;draw_texel procedure will reposition the cursor at x, y (DL, DH) ;then draw the character stored in AL ; the character colour must be stored in BL draw_textel proc push BX push AX mov ah, 02 xor al, al xor bx, bx ;display page 0 ;DH and DL are already loaded with the cursor position int 10h ;reposition the cursor pop AX ;restore the character to print mov ah, 0Ah pop BX ;restore the character colour xor bh, bh ;display page 0 mov CX, 1 ;write the character once int 10h ret draw_textel endp ;copy_screen this procedure copies one text screen to another ;REQUIREMENTS: ;The source screen 0-7, must be placed in DH ;The destination screen must be stored in DL copy_screen proc PUSH DS ;save DS mov AX, 0B800h ;place the begining of screen 0 in DS and ES mov DS, AX mov ES, AX mov AL, DH ;place the value of the source screen in BL mov BX, 4096 ;palce 4096 in BL mul BX ;multiply the value of source screen by the bytes in ;one screen and save the result in AX ;AX = AL * BL mov SI, AX ;place the offset in SI mov AL, DL ;place the value of the destination screen in BL mov BX, 4096 mul BX ;mulitply destination screen by the number of ;bytes in a screen and store the answer in AX ; AX = AL * BL mov DI, AX ;set the destination offset to the value in AX mov CX, 2000 ;place 1999 in the counter registor rep movsw ;move the word at DS:SI to ES:DI, CX times POP DS ;restore DS ret copy_screen endp ;erase_col procedure will erase the collum passes to the procedure ;in AL (0-79) ; erase_col proc mov bl, 2 ;number of bytes per collum mul bl ;AX = 2 * COL num mov di, ax mov ax, 0b800h mov es, ax ;ES:DI = top of collum to erase mov ax, 32 ;black on black space mov cx, 25 ;number of lines in collum col_loop: stosw ;place the blank into the word on the text screen add di, 158 ;move to the next line in the collum loop col_loop ret erase_col endp ;erase_line This procedure will erase a given line on the text screen ;The line to be erased is passed to the procedure in AL erase_line proc mov bl, 160 ;the number of bytes per line mul bl ;AX = line number * bytes per line mov di, ax ;place the offset of the start-of-the-line in DI mov ax, 0b800h ;the first text screen segment mov ES, ax ;ES:DI = the start of the line to erase mov ax, 32 ;black on black space mov cx, 80 ;number of spaces to blank out REP STOSW ;place 80 spaces on the line ret erase_line endp ;move_shot procedure ;this procedure will scan the text screen for < > ^ v characters and move ;them accordingly. If a ">" is found, move the shot, then skip the next word ;if a "v" is found, move a "V" into the word below it move_shot proc push ds mov ax, 0b800h mov ds, ax mov es, ax mov di, 160 ;place DS:SI and ES:DI at the start of the second line mov si, 160 begin_scan: lodsw ;load the word at DS:SI into AX and inc SI,2 cmp AL, 94 ;if AL contains the ^ (up shot) then JNE down ;(UP SHOT) mov BX, DI sub BX, 160 ;set te destination to the line above mov DS:[BX], AX ;draw the ship on the line above mov AX, 32 ;replace theold shot wth a space stosw ;erase the old shot and inc DI, 2 JMP fini down: cmp AL, 118 ;down shot "v" JNE left ;(DOWN SHOT) mov BX, DI add BX, 160 ;set DS:BX to the line below xor AL, 32 ;change the little "v" to a capital "V" mov DS:[BX], AX ;draw the ship on the line below mov AX, 32 ;place a black space in AX stosw ;erase the old ship and inc DI,2 JMP fini left: cmp, AL, 60 JNE right ;(left shot "<") dec DI dec DI ;draw the shot to the left of the current position stosw ;move ES:DI to the current position again mov AX, 32 ;place a blank space in AX stosw ;erase the old shot and inc DI, 2 JMP fini right: cmp AL, 62 JNE fini ;right shot ">" push AX mov AX, 32 ;move a blank space into AX stosw ;erase the old shot and inc di, 2 pop AX ;restore the old values stosw ;rewrite the new shot and inc DI to the next position inc SI inc SI ;place SI on the same point as DI fini: cmp di, 3840 ;if the screen has been scanned, then finish JB begin_scan ;else, scan the next WORD pop ds ret move_shot endp ; this procedure will scan through a window. It changes all of the ; characters in the window to the colours yellow on blue ; CH must contain the starting X value ; CL must contain the starting Y value of the window change_colour proc PUSH DS PUSH ES mov ax, 0b800h mov ds, ax mov es, ax xor ax, ax mov AL, CL mov BL, 160 mul BL ;AX = Y * 160 mov CL, CH xor CH, CH ;mov CH to CL and clear CH add CL, CL ;double CX add AX, CX ;AX = start of box mov SI, AX mov DI, AX mov CX, 6 ;number of lines to fill loop_it1: push cx mov CX, 25 ;number of col to fill loop_it2: lodsw mov AH, 1Eh ;colour stosw loop loop_it2 pop cx add SI, 110 ;offset of the start of one line to the next add DI, 110 ;offset of the start of one line to the next loop loop_it1 POP ES POP DS RET change_colour endp ;wait for one second wait_sec proc mov AX, 2C00h int 21h ;read in the current time mov AX, DX start_time: push AX ;place DH on the stack mov AH, 2Ch int 21h pop AX CMP DH, AH JE start_time ;else end procedure ret wait_sec endp ;wait for one hundredth of a second wait_hundsec proc mov AX, 2C00h int 21h ;read in the current time mov AX, DX hundsec_time: push AX ;place DL on the stack mov AH, 2Ch int 21h pop AX CMP DL, AL JE hundsec_time ;else end procedure ret wait_hundsec endp rain_fall proc PUSH DS STD mov AX, 0A000h mov DS, AX mov ES, AX mov SI, 63679 mov DI, 63679 mov CX, 63680 rain_loop: LODSB ;load colour into AL CMP AL, 10 JNE no_rain add DI, 320 STOSB ;draw rain down one xor AX, AX ;set display colour to 0 sub DI, 318 ;move back to original place STOSB ;erase old drop no_rain: STOSB next_rain: loop rain_loop POP DS ret rain_fall endp clear_line proc ;grpahic mode ;offset of graphic screen is in AX mov DI, AX mov AX, 0A000h mov ES, AX mov AX, 0 ;colour 0 mov CX, 320 REP STOSB ret clear_line endp clear_buffer proc key: mov AX, 0B00h int 21h CMP AL, 00 JE end_key ;no keypressed ;else remove key mov AX, 0800h int 21h JMP key end_key: ret clear_buffer endp draw_msg proc ;CX must contin the number of characters to print ;BL contains the colour to use ;DH contains the Y position ;DL contains the X position ;DS:SI contians the segment:offset of the START of ;the string to print out mov AH, 02h mov BH, 0 ;DH, DL already filled int 10h msg_loop: PUSH CX mov AH, 0Eh mov AL, DS:[SI] xor BH, BH ;BL contains the colour of text int 10h ;display number inc SI POP CX loop msg_loop ret draw_msg endp calc_off proc ;DX = Y CX = X ;answer returned in AX mov AX, 320 MUL DX add AX, CX ret calc_off endp ;CX = X DX = Y ;The offset value is returned in AX calc_offset proc mov AX, 320 MUL DX ;AX = Y * 320 add AX, CX ;AX = AX + X ret calc_offset endp draw_pix proc ;colour passed in BL ;CX contains X DX contains Y mov AX, 0A000h mov ES, AX call calc_offset ;offset of pixel returned in AX mov DI, AX ;move offset to DI mov ES:[DI], BL ;place colour at screen + offset ret draw_pix endp show_ptr proc mov AX, 0001h ;show ptr int 33h ret show_ptr endp hide_ptr proc mov AX, 0002h int 33h ret hide_ptr endp readkey proc ;returns key pressed in AL mov AX, 0800h ;readkey int 21h ret readkey endp mouse_status proc mov AX, 0003h ;check position and button status int 33h shr CX, 1 ;X position DX contains Y position ;BX returns button status ret mouse_status endp define_mouse proc ;DX points to the words definition ;BX contains the collum hot spot ;CX contains the line hot spot PUSH ES mov AX, @data mov ES, AX mov AX, 0009h ;define graphic cursor int 33h POP ES ret define_mouse endp vline proc ;BX = offset1 DX = offset2 AL = colour CMP BX, DX JB next_vline PUSH DX mov DX, BX POP BX next_vline: mov DI, BX top_vline: mov ES:[DI], AL add DI, 320 CMP DI, DX JNE top_vline ret vline endp hline proc ;ES = 0A000h BX = offset1 DX = offset2 AL = colour CMP BX, DX JB next_hline PUSH DX mov DX, BX POP BX next_hline: mov DI, BX mov CX, DX sub CX, BX REP STOSB ret hline endp set_colours proc PUSH ES mov AX, @data mov ES, AX mov AX, 1012h mov BX, 0 mov CX, 7 LEA DX, colour_table int 10h POP ES ret set_colours endp exist proc ;DS:DX points to the start of the file name, 0 terminated ;AX returns 0 if file does not exist and 1 if it does exist mov AX, 3D00h int 21h JC not_there ;does exit mov BX, AX mov AX, 3E00h int 21h ;close the file again mov AX, 1 JMP done_exist not_there: xor AX, AX done_exist: ret exist endp make_file proc ;makes an empty file ;DS:DX must point to a 0 terminated pathname ;if succesful, handle is returned in AX ;if not successful, AX = 0 mov AX, 3C00h xor CX, CX int 21h JNC made_file xor AX, AX made_file: ret make_file endp close_file proc ;handle must be passed in BX mov AX, 3E00h int 21h ret close_file endp delete_file proc ;DS:DX points to a 0 terminated filename mov AX, 4100h int 21h ret delete_file endp open_file proc ;DS:DX points to a 0 terminated filename ;returns handle in AX mov AX, 3D02h int 21h ret open_file endp read_file proc ;BX = handle CX = number of bytes to read ;DS:DX points to the buffer to be filled ;AX returns the number of bytes read! mov AX, 3F00h int 21h ret read_file endp write_file proc ;BX = handle CX = number of bytes to write ;DS:DX points to the string of bytes to write out. mov AX, 4000h int 21h ret write_file endp check_for_input proc ;see if user has pressed a key or mouse button mov AX, 0B00h int 21h ;check keyboard buffer CMP AL, 0 JE next_check mov AX, 0800h ;if key pressed, clear buffer int 21h mov AX, 1 JMP end_check next_check: mov AX, 0003h int 33h ;get mouse status AND BX, 0007h ;leave last three bits of BUTTON STATUS CMP BX, 0 JE done_check mov AX, 1 JMP end_check done_check: XOR AX, AX ;set AX to 0 end_check: ret check_for_input endp get_param proc ;loads any command line arguments into ES:DI ;the max size of the buffer is passed in CX PUSH DS PUSH ES PUSH DI PUSH CX mov AX, 2F00h int 21h ;get DTA address ES:BX xor CX, CX ;clear CX mov CL, ES:[BX] ;the number of characters after the filename CMP CL, 2 ;if no parameters, return to caller JB end_param dec CL ;remove white space POP BX ;BL = max size of buffer CMP CL, BL ;if character string > max size make it the max size JB next_param_2 mov CL, BL next_param_2: mov AX, ES mov DS, AX ;make DS = ES mov SI, BX ;DS:SI = DTA inc SI inc SI ;DS:SI points to the start of the parameter list POP DI ;the offset of the buffer POP ES ;pointer to the data segment REP movsb ;copy paramters to buffer end_param: POP DS ret get_param endp letter_count proc ;counts the number of characters in the string passed in DS:SI ;the number of characters is returned in CX ;letter_count stops when it hits a '$' or NULL xor CX, CX start_letter: mov AL, DS:[SI] ;load character into AL cmp AL, 36 JE end_letter ;if '$' is found, end count CMP AL, 0 JE end_letter ;if NULL is found, end count inc CX ;if not end of string, inc letter counter inc SI ;move to next character JMP start_letter end_letter: ret letter_count endp word_count proc ;takes the string passed in at DS:SI and returns the number ;of words in the list in CX ;word_count stops when it hits a '$' or NULL xor CX, CX ;set word count to 0 start_count: mov AL, DS:[SI] ;load character into AL cmp AL, 36 JE end_count ;if '$' is found, end count CMP AL, 0 JE end_count ;if NULL is found, end count cmp AL, 32 JNE next_count ;if character = space inc SI mov AL, DS:[SI] ;move next character into AL dec SI ;return to current character cmp AL, 32 ;if next character is also space, it isn't a parameter JE next_count inc CX ;if character isn't a space, inc count next_count: inc SI ;move to next character JMP start_count ;perform for again end_count: ret count_param endp clean_up proc ;clears the keyboard buffer and clears the text screen start_clear: mov AX, 0B00h int 21h ;check for key in buffer CMP AL, 0 ;if keypressed, clear buffer JE next_clear mov AX, 0800h int 21h ;read next key in buffer JMP start_clear ;check for next key next_clear: mov AX, 0003h ;screen function 0, screen 3 int 10h ;clear text screen ret clean_up endp small_wait proc mov AX, 8600h ;CX:DX contains the time to wait in mircoseconds ;CX = 200 waits for 32 seconds ;CX = 100 waits for 16 seconds int 15h ;CX = 10 waits for 2 seconds ret small_wait endp ;hides the text cursor hide_cursor proc mov ax, 0200h mov bh, 0 mov DH, 25 mov DL, 80 int 10h ret hide_cursor endp ;fills the screen with random DH-coloured characters ;ES points to the text screen fill_screen proc xor DI, DI mov CX, 2000 fill_loop: PUSH CX PUSH DX xor CX, CX call small_wait call get_time POP DX mov AH, DH ;DH colours mov AL, DL inc AL ;make sure character is not 0 STOSW POP CX loop fill_loop ret fill_screen endp ;This proc accepts pointers to two strings. It checks for the occuance ;of the string pointed to by DS:DI INSIDE the string pointed to by DS:SI ;BOTH strings are 0 OR '$' terminated. ;If the sub-string is found, its starting position ;(offset) is returned in CX ;If no occuance is found, AX returns 0 else AX = 1 ;SI and DI are saved and are returned as they were passed in sub_str proc xor CX, CX PUSH DI PUSH SI xor AX, AX start_substr: mov DH, DS:[DI] ;sub string mov DL, DS:[SI] ;main string ;test for end of string CMP DH, 36 JE end_substr CMP DL, 36 JE end_substr CMP DH, 0 JE end_substr CMP DL, 0 JE end_substr CMP DH, DL JNE next_substr inc SI inc DI mov AX, 1 JMP start_substr next_substr: POP SI POP DI PUSH DI PUSH SI inc CX ;add one to starting place add SI, CX xor AX, AX JMP start_substr end_substr: POP DI POP SI ;CMP AX, 0 ;JNE done_substr ;if AX = 0 then clear CX ; xor CX, CX done_substr: ret sub_str endp ;This procedure erases the graphic screen (13h) line pointed ;to by ES:DI. The colour used to clear the line is passed in AX ;The ES and AX registers are returned the same. The CX reg is destroyed. erase_line proc mov CX, 320 REP stosb ret erase_line endp ;This procedure clears the graphic (013h) screen. The first line (0) ;is erased and the bottom line (199) is erased. Each even line from the ;top is then cleared as is each odd line from the bottom. ;This procedure uses the wait_hundsec proc and the erase_line proc ;The ES register is saved and returned. pull_blinds proc PUSH ES mov AX, 0A000h mov ES, AX ;ES points to graphic screen xor BX, BX ;BX contains the offset of the first line mov DX, 63680 ;DX contains the offset of the last line xor AX, AX ;set AX to colour 0 mov CX, 100 ;number of lines to clear / 2 blinds_top: PUSH CX mov DI, BX ;move top offset into DI call erase_line add BX, 640 ;skip line mov DI, DX ;bottom line into DI call erase_line sub DX, 640 ;skip up a line PUSH AX PUSH BX PUSH CX PUSH DX call wait_hundsec call wait_hundsec POP DX POP CX POP BX POP AX POP CX loop pull_blinds_top POP ES ret pull_blinds endp ;This proc saves the current text screen (0) to ;the address pointed to by ES:DI. ;DS is not changed by this proc. ;Note: the destination buffer must be 4096 bytes long. save_text proc CLD PUSH DS mov AX, 0B800h mov DS, AX ;point DS to text screen xor SI, SI ;DS:SI points to start of screen mov CX, 4096 ;bytes of text screen REP movsb ;move 4096 bytes from DS:DI to ES:DI POP DS ret save_text endp ;This proc copies the contents of the buffer pointed to by DS:SI ;to the text screen (0). The ES reg is not changed by this proc. ;Note: The buffer at DS:SI must be 4096 bytes long. restore_text proc CLD PUSH ES mov AX, 0B800h mov ES, AX xor DI, DI ;ES:DI points to the first text screen mov CX, 4096 REP movsb ;move 4096 bytes from DS:SI to the text screen POP ES ret restore_text endp ; This proc reads in a line from a text file. The ; proc stops reading when it hits #13. It then reads one more ; character (#10). The proc also stops when end of file is reached. ; The #13, #10 are replaced by #0 and '$'. If eof is reached ; first, the #0,'$' are appended to the line. ; BX must hold the file handle. ; DS:SI must point to the start of the buffer to hold the line. ; DS:DX must point to a one-byte buffer. ; Note: DS:SI still points to the buffer when proc is finished. ; Number of character read is returned in CX 0 = eof file_get_line proc PUSH SI mov DI, DX ; DS:DI points to one byte buffer xor CX, CX ; characters read file_get_line_start: PUSH CX mov CX, 1 ; read one byte call read_file ; read oen byte into temp_buffer POP CX CMP AX, 0 ; 0 bytes read, eof JE file_get_line_append inc CX mov AL, DS:[DI] ; get newly read character CMP AL, 13 ; if #13 found, then JNE file_get_line_okay mov CX, 1 call read_file ; read in #10 JMP file_get_line_append file_get_line_okay: mov DS:[SI], AL ; move character into string buffer inc SI ; goto next character position JMP file_get_line_start file_get_line_append: mov AL, 0 mov DS:[SI], AL ; append #0 inc SI mov AL, 36 mov DS:[SI], AL ; append '$' POP SI ret file_get_line endp ; This proc makes a string upper case. ; The address of the string is passed in DS:SI ; The function stops when it hits a '$' or 0 character. upper_case_line proc upper_case_line_start: mov AL, DS:[SI] CMP AL, 0 JE upper_case_line_ender CMP AL, 36 ; "$" JE upper_case_line_ender CMP AL, 97 JB upper_case_line_next CMP AL, 122 JG upper_case_line_next xor AL, 32 mov DS:[SI], AL upper_case_line_next: inc SI JMP upper_case_line_start upper_case_line_ender: ret upper_case_line endp ; BEFORE USING THIS PROC YOU MUST ADD THE FOLLOWING LINES ; TO THE TOP OF YOUR PROGRAM! ; mov BX, size_of_exe_file_in_bytes ; call realloc ; WHERE ES ALREADY POINTS TO THE CORRECT MEMORY ; WHERE "size of .exe file" IS THE SIZE OF YOUR PROGRAM BEFORE ; ADDING THESE TWO LINES ; "realloc" MUST BE INCLUDED IN YOUR PROGRAM. ; WITHOUT THESE REQUIREMENTS NO MEMORY ALLOCATION WILL WORK! ; This proc allocated a block of dynamic memory. ; The number of bytes to be allocated is passed in BX. ; If the function is successful, AX returns the ; SEGMENT pointer. This should not be confused with the ; OFFSET pointer. The return value should NOT be modified. ; The return value should be stored in ES or DS and ; used with a seperate offset register (SI or DI). ; If malloc fails, then AX returns 0. malloc proc shr BX, 1 shr BX, 1 shr BX, 1 shr BX, 1 ; change BX from bytes to paragraphs ( div 16 ) inc BX ; round up, to insure enough memory mov AX, 4800h int 21h JNC malloc_end ; if no problems, jump to end xor AX, AX ; if error, set AX to 0 malloc_end: ret malloc endp ; BEFORE USING THIS PROC YOU MUST ADD THE FOLLOWING LINES ; TO THE TOP OF YOUR PROGRAM! ; mov BX, size_of_exe_file_in_bytes ; call realloc ; WHERE ES ALREADY POINTS TO THE CORRECT MEMORY ; WHERE "size of .exe file" IS THE SIZE OF YOUR PROGRAM BEFORE ; ADDING THESE TWO LINES ; "realloc" MUST BE INCLUDED IN YOUR PROGRAM. ; WITHOUT THESE REQUIREMENTS NO MEMORY ALLOCATION WILL WORK! ; This proc frees up a segment of memory previously ; allocated. The segment to be freed must be passed ; in ES. ; Note: Unlike C's free() calling this proc incorrectly should ; not crash your program. free proc mov AX, 4900h int 21h ret free endp ; BEFORE USING THIS PROC YOU MUST ADD THE FOLLOWING LINES ; TO THE TOP OF YOUR PROGRAM! ; mov BX, size_of_exe_file_in_bytes ; call realloc ; WHERE ES ALREADY POINTS TO THE CORRECT MEMORY ; WHERE "size of .exe file" IS THE SIZE OF YOUR PROGRAM BEFORE ; ADDING THESE TWO LINES ; "realloc" MUST BE INCLUDED IN YOUR PROGRAM. ; WITHOUT THESE REQUIREMENTS NO MEMORY ALLOCATION WILL WORK! ; This proc allocated a block of dynamic memory and ; sets all of the bytes equal to the value in DL. ; The number of bytes to be allocated is passed in BX. ; If the function is successful, AX returns the ; SEGMENT pointer. This should not be confused with the ; OFFSET pointer. The return value should NOT be modified. ; The return value should be stored in ES or DS and ; used with a seperate offset register (SI or DI). ; If calloc fails, then AX returns 0. ; DL should contain the byte to be copied into the ; new block. calloc proc PUSH ES PUSH DX mov CX, BX ; copy number of bytes into CX cld ; clear direction flag shr BX, 1 shr BX, 1 shr BX, 1 shr BX, 1 ; change BX from bytes to paragraphs ( div 16 ) inc BX ; round up, to insure enough memory mov AX, 4800h int 21h JC calloc_error ; if problems, jump to error mov ES, AX POP AX ; POP byte code into AL xor DI, DI ; set ES:DI to point to new memory rep stosb ; copies code in AL CX times into new memory mov AX, ES ; move segment pointer back into AX JMP calloc_end calloc_error: xor AX, AX ; if error, set AX to 0 calloc_end: POP ES ret calloc endp ; BEFORE USING THIS PROC YOU MUST ADD THE FOLLOWING LINES ; TO THE TOP OF YOUR PROGRAM! ; mov BX, size_of_exe_file_in_bytes ; call realloc ; WHERE ES ALREADY POINTS TO THE CORRECT MEMORY ; WHERE "size of .exe file" IS THE SIZE OF YOUR PROGRAM BEFORE ; ADDING THESE TWO LINES ; "realloc" MUST BE INCLUDED IN YOUR PROGRAM. ; WITHOUT THESE REQUIREMENTS NO MEMORY ALLOCATION WILL WORK! ; This proc changes the size of a segment of dynamic memory. ; The proc acts very much like C's realloc(). However, if an ; error occures, your memory is not lost. No temporary ; storage is required. ; To use this proc, ES must point to the memory segment to ; change. BX must contain the number of bytes the new ; block will be. ; On success, ES will point to the new block and AX will ; be NON-ZERO. If the proc fails, ES will point to the ; old memory segment and AX will equal 0. realloc proc shr BX, 1 shr BX, 1 shr BX, 1 shr BX, 1 ; convert from bytes to paragraphs (div 16) inc BX ; round up one paragraph to insure enough memory mov AX, 4A00h int 21h JC realloc_error mov AX, 1 ; function succeeded, make AX non-zero JMP realloc_end realloc_error: xor AX, AX ; error, set AX to 0 realloc_end: ret realloc endp ; Used to manulipuate linked lists ; This proc creates a List structure. It accepts the size ; of the node data in CX. ; If successful, the proc returns a ptr to the new List ; structure in AX. On failure, AX returns 0 create_list proc PUSH ES PUSH CX cld ; clear direction flag mov BX, 4 ; size of alloc xor DX, DX ; set all bytes in struct to 0 call calloc POP CX ; restore CX CMP AX, 0 ; if calloc failed, return AX = 0 JE create_list_end mov ES, AX ; move pointer into ES xor DI, DI ; ES:DI point to start of list struct mov AX, CX stosw ; move AX into the "size" part of the list struct mov AX, ES ; put pointer back into AX create_list_end: POP ES ; restore ES ret create_list endp ; This proc deletes all nodes in a list, then deletes the ; list. The address of the list must be passed in ES. delete_list proc mov AX, ES ; move list pointer into AX CMP AX, 0 ; if no list JE delete_list_end PUSH ES ; save the address of the list struct mov DI, 2 ; ES:DI points to the "first" variable. mov AX, ES:[DI] ; move "first" into AX delete_list_start: CMP AX, 0 ; if no node, then jump to the end JE delete_list_list mov ES, AX ; move node address into ES xor DI, DI ; ES:DI point to the next node mov BX, ES:[DI] ; move address of next node into BX call free ; free current node mov AX, BX ; move address of next node into AX JMP delete_list_start delete_list_list: POP ES call free ; delete list struct delete_list_end: ret delete_list endp ; This proc creates a node for a linked list. The linked-list ; structure must be passed in ES. ; The node will be created an initalized. On success, the ; address of the new node will be returned in AX. ; If an error occures, AX will contain 0. create_node proc xor DI, DI ; set ES:DI to point to the size of the data mov BX, ES:[DI] ; move size of data to allocate into BX inc BX inc BX ; node size is the size of data + 2 xor DX, DX ; set all bytes of the node to 0 call calloc ; create node, set all cells to 0 ; the pointer in AX is returned. On error AX will contain 0. ret create_node endp ; This proc removes a node from a linked list. ; ES must point to the linked-list structure and ; DX must point to the node to delete. ; The proc will unlink the node and free up the ; memory used by the node. ; Note: The node does not have to be in the list, it will still be deleted. ; ; DS and ES are maintained after the call. ; DX is undefined after this call. delete_node proc PUSH ES mov DI, 2 ; ES:DI point to "first" pointer. mov AX, ES:[DI] ; AX contains ptr to first node. CMP AX, 0 ; if no node, jump to deltetion JE delete_node_delete delete_node_next: mov ES, AX ; ES points to current node xor DI, DI ; DI points to "next" node mov AX, ES:[DI] ; AX contains pointer to next node CMP AX, 0 ; if no next node JE delete_node_delete CMP AX, DX ; if next node is target, then unlink JNE delete_node_next delete_node_unlink: PUSH ES ; save "previous" node mov AX, DX mov ES, AX ; move to-delete node pointer in ES xor DI, DI ; ES:[DI] point to "next" pointer. mov AX, ES:[DI] ; AX contains address of next node POP ES ; restore ptr to previous node mov ES:[DI], AX ; "previous" node pointer to node after deleted node delete_node_delete: mov AX, DX mov ES, AX ; put pointer in ES for deleting call free POP ES ret delete_node endp ; This proc copies the data passed in DS:SI to the ; node addressed by AX. The address of the linked-list ; structure must be passed in ES. ; AX = node ES = list DS:SI = source data ; DS and ES are saved and remain the same after the call. set_data proc PUSH ES CLD ; clear direction flag xor DI, DI ; ES:DI points to the size value mov CX, ES:[DI] ; move data size into CX mov ES, AX ; move pointer to node into ES mov DI, 2 ; ES:DI points to the node's "data" space rep movsb ; copy CX bytes from DS:SI into ES:DI POP ES ret set_data endp ; This proc gets the data from a node of the linked-list ; and copies the data into a buffer. The buffer must ; be large enough to hold the data. ; ES:DI must point to the buffer to receive the data. ; AX must point to the node that holds the data. ; DS must point to the liked-list structure. ; Note: Both ES and DS are saved and remain the same after the call. get_data proc PUSH DS CLD ; clear direction flag xor SI, SI ; DS:SI points to the "size" variable. mov CX, DS:[SI] ; size is copied into CX mov DS, AX ; DS points to the node containing the data mov SI, 2 ; DS:SI points to data to be copied REP movsb ; copy CX bytes from data into the buffer POP DS ret get_data endp ; This proc adds a node to the start of the linked list. ; The address of the node is passed in DX. ; The address of the linked-list structure is passed in ES ; ES is saved and still holds the list struct after the call. add_node proc PUSH ES mov DI, 2 ; ES:DI points to the "first" variable mov BX, ES:[DI] ; BX contains ptr to the old first node mov ES:[DI], DX ; copy address of new node into "first" mov AX, DX mov ES, AX ; ES points to new first node xor DI, DI ; ES:DI point to "next" variable of new node mov ES:[DI], BX ; make new first node point to old first node POP ES ret add_node endp ; This proc inserts a node into the middle of a linked list. ; The new node is placed after the last node with a value less ; than or equal to the new node. ; Otherwise the node is passsed at the end of the list. ; The address of the new node is passed in DX. ; The address of the linked list structure is passed in ES ; Note: ES is not changed by this proc. insert_node proc PUSH ES PUSH ES mov AX, DX mov ES, AX ; ES points to new node mov DI, 2 ; ES:DI point to the first byte of "data" mov BL, ES:[DI] ; BL = first cell of data POP ES ; ES = address of linked-list structure mov DI, 2 ; ES:DI points to the "first" variable mov AX, ES:[DI] ; AX points to node insert_node_start: CMP AX, 0 ; if no next node, then add in node JE insert_node_add_node mov ES, AX ; ES points to node mov DI, 2 ; ES:DI points to node data mov BH, ES:[DI] ; BH contains current node data CMP BL, BH ; if new data is greater than or equal to current JG insert_node_pre_add ; then add in new node xor DI, DI ; ES:DI points to "next" variable mov AX, ES:[DI] ; AX contains ptr to next node JMP insert_node_start insert_node_pre_add: xor DI, DI ; ES:DI points to "next" variable insert_node_add_node: mov ES:[DI], DX ; place address of new node in "next" POP ES ret insert_node endp ; This proc appends a node to the end of the linked list. ; ES should point to the linked list structure. ; DX points to the new node to append. ; ES is saved and is returned still pointing to list structure. append_node proc PUSH ES mov DI, 2 ; ES:DI points to the "first" variable mov AX, ES:[DI] ; AX is a pointer to the first node append_node_start: CMP AX, 0 ; if no next node then copy in pointer JE append_node_attach mov ES, AX xor DI, DI ; make ES:DI point to the "next" variable mov AX, ES:[DI] ; AX points to next node JMP append_node_start append_node_attach: mov ES:[DI], DX ; put address of new node in "next" variable POP ES ret append_node endp ; This proc takes a pointer to the first ; node in the linked list. The address of the ; list structure is passed in ES. The address of the ; first node is returned in AX. ; If there is no first node, AX returns 0. ; If there is no linked-list structure, AX is undefined. ; Note: ES is maintained as a pointer to the list structure. goto_first_node proc mov DI, 2 ; ES:DI points to "first" variable. mov AX, ES:[DI] ; return AX with the first node address. ret goto_first_node endp ; This proc accepts a pointer to a node. ; The proc returns a pointer to the next node in the list. ; The address of the current node is passed in ES. ; AX will return the value of the next node. goto_next_node proc xor DI, DI ; ES:DI points to the "next" variable mov AX, ES:[DI] ; AX returns the address of the next node ret goto_next_node endp ; This proc accepts a pointer to a linked-list struct in ; ES. The proc then returns the size of the data buffer of ; each node ( in bytes ) in CX. get_data_size proc xor DI, DI ; ES:DI points to size variable mov CX, ES:[DI] ; CX = size of data buffer in bytes ret get_data_size endp ; This proc accepts a pointer to the linked list and a pointer ; to a data buffer to match. The proc then searches the linked list ; for a node that matches the data buffer. The length to match ; is passed in CX. If CX = 0 then the whole buffer is compared. ; ES points to the linked-list structure. ( kept after call ) ; DS:SI points to the buffer to compare. ( DS:SI is also kept after call ) ; ( optional ) CX = length of buffer to compare; otherwise CX = 0 ; This proc returns the pointer to the matching node in AX. ; If no match is found, AX returns 0. find_data proc PUSH ES CMP CX, 0 ; if CX = 0, use default size JNE find_data_start xor DI, DI ; ES:DI point to "size" variable mov CX, ES:[DI] ; CX = size of buffer find_data_start: mov DI, 2 ; ES:DI point to "first" variable mov AX, ES:[DI] ; AX = pointer to first node find_data_new_node: CMP AX, 0 ; if no node, jump out JE find_data_end mov ES, AX ; ES points to current node mov DI, 2 ; ES:DI point to "data" PUSH CX call mem_cmp ; compare buffer to data POP CX CMP DX, 0 ; if match, then jump to end JE find_data_end xor DI, DI ; ES:DI points to next node mov AX, ES:[DI] ; AX points to next node JMP find_data_new_node find_data_end: POP ES ret find_data endp ; This proc compares two pieces of memory. ; The two byte-buffers are passed in DS:SI and ES:DI ; Both addresses are saved and the pointers are returned the same as they ; were passed in. ; CX contains the number of bytes to compare. ( not maintained ) ; If the two buffers are equal up to CX bytes, then DX = 0 ; If the DS:SI buffer is higher, then DX = 1 ; If the ES:DI buffer is higher, then DX = 2 ; Note: AX is not changed, however, BX, CX and DX are changed. mem_cmp proc PUSH SI PUSH DI xor DX, DX ; assume equal, until proven different mem_cmp_start: CMP CX, 0 JE mem_cmp_end mov BH, DS:[SI] ; move byte of first buffer into BH mov BL, ES:[DI] ; move byte of second buffer into BL CMP BH, BL JG mem_cmp_first_greater CMP BH, BL JB mem_cmp_second_greater dec CX inc SI inc DI ; move to next byte, dec counter JMP mem_cmp_start mem_cmp_first_greater: mov DX, 1 JMP mem_cmp_end mem_cmp_second_greater: mov DX, 2 mem_cmp_end: POP DI POP SI ret mem_cmp endp