;***************************************************************************** ; This program is designed to show how to input a string from the keyboard and ; and print a string on the monitor. This program must be linked to the ; kernel32.lib in order to work. ; ; Written by Joe Toone 7/9/2003 8:25:12 PM ;***************************************************************************** TITLE io32.asm ;file name of program LF equ 0ah ;ASCII 10 - newline character CR equ 0dh ;ASCII 13 - carriage return character MAXSTR equ 256d ;Accept up to 256 characters ENABLE_PROCESSED_INPUT equ 1 ;Flag to turn off line buffering ENABLE_PROCESSED_OUTPUT equ 1 ;Flag to turn off line bufferin ENABLE_LINE_WRAP equ 3 ;Flag to trun line wrap on DISABLE_PROCESSED_INPUT equ 7 ;Flag to turn on line buffering STD_INPUT equ -10d ;Function number for keyboard input STD_OUTPUT equ -11d ;Function number for monitor output .586 ;Allow for Pentium instrucitons .MODEL FLAT ;Memory model is FLAT (4GB) INCLUDELIB kernel32.lib ;Include the kernel 32 library SetConsoleMode PROTO NEAR32 stdcall, ;Prototype for attaching to console hConsoleHandle:DWORD, dwMode:DWORD GetStdHandle PROTO NEAR32 stdcall, ;Prototype for obtaining a file handle nStdHandle:DWORD ReadFile PROTO NEAR32 stdcall, ;Prototype for reading a file hFile:DWORD, lpBuffer:NEAR32, nNumberOfCharsToRead:DWORD, lpNumberOfBytesRead:NEAR32, lpOverlapped:NEAR32 WriteFile PROTO NEAR32 stdcall, ;Prototype for writing a file hFile:DWORD, lpBuffer:NEAR32, nNumberOfCharsToWrite:DWORD, lpNumberOfBytesWritten:NEAR32, lpOverlapped:NEAR32 ExitProcess PROTO NEAR32 stdcall, ;Prototype for Exit of OS dwExitCode:DWORD .STACK 4096h ;4k hex bytes for stack .DATA ;Data segment begins here Menu BYTE LF,LF,CR,'[1] Character I/O',CR,LF BYTE '[2] String I/O',CR,LF BYTE '[3] ASCII to Integer and Integer to ASCII',CR,LF BYTE '[4] Exit',CR,LF,LF BYTE 'Your Selection Please? ',0 CharInput BYTE CR,LF,'Type a character please --> ',0 StrInput BYTE CR,LF,'Type a String please --> ',0 Result BYTE LF,LF,CR,'So you decided to type ==> ',0 Error BYTE CR,LF,LF,"On the Menu, there ain't no stinkin -> ",0 InputNum BYTE CR,LF,LF,'Enter an integer (less than 4294967295) --> ',0 Result1 BYTE CR,LF,LF,'The number preceeding ',0 Result2 BYTE ' is ',0 Result3 BYTE ' and the following number is ',0 NewLine BYTE LF,LF,CR,0 UserString BYTE MAXSTR dup(?) AsciiNum BYTE MAXSTR dup(0) KeyPress BYTE ? CharBuffer BYTE ? SaveNumber DWORD 0h OneLess DWORD 0h OneMore DWORD 0h strAddr DWORD ? strLength DWORD ? hStdOut DWORD ? hStdIn DWORD ? read DWORD ? written DWORD ? ;************************** Main Body of Program ***************************** ; Given : Nothing ; Process: Main Body - calls procedures to do the processing ; Return : Nothing ;***************************************************************************** .CODE ;executable section begins here _main: lea esi,Menu ;point to the question prompt call PrintString ;go print the string lea esi,CharBuffer ;pointer to character buffer in data call GetChar ;get the character mov al,CharBuffer ;copy character to AL mov KeyPress,al ; and save a copy in KeyPress cmp KeyPress,'1' ;was 1 typed? je DoCharIO ; yes, do the character thing cmp KeyPress,'2' ;was 2 typed? je DoStringIO ; yes, do the string thing cmp KeyPress,'3' ;was 3 typed? je DoAsciiInt ; yes, do the string thing cmp KeyPress,'4' ;was 4 typed? je ByeBye ; yes, we're outta here. lea esi,Error ;else point to the error string call PrintString ; go print the string lea esi, CharBuffer ; and what they typed call PutChar ; jmp _main ;jump back to the menu for another try DoCharIO:lea esi, CharInput ;pointer to character buffer call PrintString ;go print the string lea esi,CharBuffer ;pointer to UserString in data call GetChar ;get the character input jmp ShowResult ;go print the result DoStringIO:lea esi, StrInput ;pointer to character buffer call PrintString ;go print the string lea esi,UserString ;pointer to UserString in data call GetString ;get the string jmp ShowResult ;go print the result DoAsciiInt:lea esi, InputNum ;pointer to get number prompt call PrintString ;go print the screen lea esi,AsciiNum ;pointer to AsciiNum in data call GetString ;get the string lea esi,AsciiNum ;pointer to AsciiNum in Data lea edi,SaveNumber ;pointer to DWORD storage in data call Ascii2Int ;Convert the string to integer mov eax,SaveNumber ;Copy number to eax mov OneMore,eax ;Copy number to OneMore variable inc OneMore ; and add one to it mov OneLess,eax ;Copy number to OneLess variable dec OneLess ; and subtract one from it call IntResult ;Go display all the number stuff jmp NextMenu ;go back to the menu ShowResult:lea esi, Result ;pointer to result message call PrintString ;go print the string cmp KeyPress,'2' ;if we are doing strings, je StrOut ; then go print the UserString lea esi, CharBuffer ;else point to their character call PutChar ; and print it jmp NextMenu ; then go to the menu StrOut: lea esi, UserString ;pointer to string buffer call PrintString ;go print the string NextMenu:jmp _main ;go back to the menu ByeBye: INVOKE ExitProcess, 0 ; exit with return code 0 ;********************* Near procedure to get a String ************************* ; Given : The Address of the String to fill in ESI register ; Process : Input the String using the kernel32.lib ReadFile from the ; : Standard_Input function call. No registers are changed and the ; : flags are not affected. ; Return : The input string in the data segment ;****************************************************************************** GetString PROC NEAR32 ; Define procedure pushad ; save all registers pushfd ; save flags INVOKE GetStdHandle,STD_OUTPUT ; get handle for console mov hStdOut, eax ; save the handle INVOKE SetConsoleMode, ; invoke standard console with hStdOut, ; file handle for keyboard ENABLE_LINE_WRAP ; turn line wrap on INVOKE GetStdHandle,STD_INPUT ; get handle for console mov hStdIn, eax ; save the handle INVOKE SetConsoleMode, ; invoke standard console with hStdIn, ; file handle for keyboard DISABLE_PROCESSED_INPUT ; turn line buffering on mov ecx, MAXSTR ; string length mov strLength, ecx ; maximum string to accept mov strAddr, esi ; save pointer to input string INVOKE ReadFile, ; invoke standard ReadFile with hStdIn, ; file handle for keyboard strAddr, ; address of string strLength, ; length of string NEAR32 PTR read, ; variable for # bytes read 0 ; overlapped mode mov ecx, read ; number of bytes read mov BYTE PTR [esi+ecx-2],0 ; replace CR/LF by trailing null popfd ; restore flags popad ; restore registers ret ; return to caller GetString ENDP ;******************* NEAR32 procedure to print a string *********************** ; Given : The Address of Null (0) terminated String to print in ESI register ; Process : Print the String using the kernel32.lib WriteFile to ; : Standard_Output function call. No registers are changed and the ; : flags are not affected. ; Return : Nothing ;****************************************************************************** PrintString PROC NEAR32 pushad ; save registers pushfd ; save flags mov strAddr, esi ; copy string address ; find string length mov strLength, 0 ; initialize string length WhileChar: cmp BYTE PTR [esi], 0 ; character = null? jz EndWhileChar ; exit if so inc strLength ; increment character count inc esi ; point at next character jmp WhileChar ; while more characters exist EndWhileChar: INVOKE GetStdHandle,STD_OUTPUT ; get handle for console output mov hStdOut, eax ; copy file handle for screen INVOKE WriteFile, ; invoke standard WriteFile with hStdOut, ; file handle for screen strAddr, ; address of string strLength, ; length of string NEAR32 PTR written, ; variable for # bytes written 0 ; overlapped mode popfd ; restore flags popad ; restore registers ret ; return to caller PrintString ENDP ;********************* Near procedure to get a Character ********************** ; Given : The Address of the Character to get in ESI register ; Process : Input the Character using the kernel32.lib ReadFile from the ; : Standard_Input function call. No registers are changed and the ; : flags are not affected. ; Return : The input character in the data segment ;****************************************************************************** GetChar PROC NEAR32 ; Define procedure pushad ; save all registers pushfd ; save flags INVOKE GetStdHandle,STD_INPUT ; get handle for keyboard mov hStdIn, eax ; save the handle INVOKE SetConsoleMode, ; invoke standard console with hStdIn, ; file handle for keyboard ENABLE_PROCESSED_INPUT ; turn line buffering off INVOKE ReadFile, ; invoke standard ReadFile with hStdIn, ; file handle for keyboard esi, ; address of character 1, ; length of one byte NEAR32 PTR read, ; variable for # bytes read 0 ; overlapped mode call PutChar ; echo the character on screen popfd ; restore flags popad ; restore registers ret ; return to caller GetChar ENDP ;******************* NEAR32 procedure to print a Character ******************** ; Given : The Address of the Character to print in ESI register ; Process : Print the Character using the kernel32.lib WriteFile to ; : Standard_Output function call. No registers are changed and the ; : flags are not affected. ; Return : Nothing ;****************************************************************************** PutChar PROC NEAR32 ; Define procedure pushad ; save registers pushfd ; save flags INVOKE GetStdHandle,STD_OUTPUT ; get handle for console output mov hStdOut, eax ; copy file handle for screen INVOKE SetConsoleMode, ; invoke standard console with hStdOut, ; file handle for screen ENABLE_PROCESSED_OUTPUT ; turn line buffering off INVOKE WriteFile, ; invoke standard WriteFile with hStdOut, ; file handle for screen esi, ; address of character 1, ; length of one byte NEAR32 PTR written, ; variable for # bytes written 0 ; overlapped mode popfd ; restore flags popad ; restore registers ret ; return to caller PutChar ENDP ;**************** Procedure to Convert ASCII to Integer *********************** ; Given : A pointer to the string to be Converted in the ESI register and a ; : pointer to the destination integer in EDI ; Process : Convert the string of ASCII digits to an integer and store the ; : string in the address pointed to by EDI. No registers are changed ; : and the flags are not affected. ; Return : Nothing ;****************************************************************************** Ascii2Int PROC NEAR32 pushad ;Save the contents of all registers pushfd ; cld ;Set the direction flag for forward mov ebx,0h ;Zero the EBX register xor eax,eax ;Clear the EAX register NextIn: lodsb ;Get a character from the string cmp al,'0' ;If the character is less than 0, then jl Done ; we have all the number and are Done cmp al,'9' ;If the character is more than 9, then jg Done ; we have all the number and are Done and al,0Fh ;Mask out the high 4 bits, converting to Int xor ah,ah ;Zero the high byte of AX push eax ;Save the digit on the stack mov eax,10d ;Place 10 decimal in AX to multiply by mul ebx ;Multiply the number by 10 mov ebx,eax ;Get number from EAX and put in EBX pop eax ;Get the digit back from the stack add ebx,eax ;Add the digit to the number jmp NextIn ;Get the next digit Done: mov [edi],ebx ;Save NUMBER at address pointed to by EDI popfd ;Restore the registers popad ; ret ;Return to Calling procedure Ascii2Int ENDP ;**************** Procedure to Convert Integer to ASCII *********************** ; Given : A pointer to the integer to be Converted in the ESI register and a ; : pointer to the destination string in EDI ; Process : Convert the integer to a string of ASCII digits and store the ; : string in the address pointed to by EDI. No registers are changed ; : and the flags are not affected. ; Return : Nothing ;****************************************************************************** Int2Ascii PROC NEAR32 pushad ;Save the contents of all registers pushfd ; cld ;Set the direction flag for forward mov eax,[esi] ;copy the integer to eax mov ecx,0h ;Zero the CX register for digit counter mov ebx,10d ;Set up divisor of 10 decimal NextOut:mov edx,0h ;Zero EDX reg for high order dword of div div ebx ;Divide number in EAX by 10d push edx ;Save remainder on the stack inc ecx ;Count the digit cmp eax,0h ;Is number in EAX greater than 0 jg NextOut ;Yes, get next digit CharOut:pop eax ;Get number from the stack or eax, 0030h ;Convert Int to Ascii by adding 30h stosb ; and store in the destination string dec ecx ;Reduce characters to print by one jnz CharOut ;If CX > 0 loop to print next digit mov al,0 ;Place a NULL in AL stosb ; and null terminate the string popfd ;Restore the registers popad ; ret ;Return to Calling procedure Int2Ascii ENDP ;************************ Procedure Output the Result ************************* ; Given : Nothing ; Process : Display a Formatted String containing the Calculated Numbers ; Return : Nothing ;****************************************************************************** IntResult PROC NEAR32 pushad ;Save the contents of all registers pushfd ; lea esi,Result1 ;Address of Result1 string call PrintString ;Display the string lea esi,SaveNumber ;Point to original number lea edi,AsciiNum ;Point to temp location for ASCII number call Int2Ascii ;Convert the integer to ascii lea esi,AsciiNum ;Point to the temp ascii number call PrintString ; and go print it lea esi,Result2 ;Address of Result2 string call PrintString ;Display the string lea esi,OneLess ;Point to decremented number lea edi,AsciiNum ;Point to temp location for ASCII number call Int2Ascii ;Convert the integer to ascii lea esi,AsciiNum ;Point to the temp ascii number call PrintString ; and go print it lea esi,Result3 ;Address of Result3 string call PrintString ;Display the string lea esi,OneMore ;Point to incremented number lea edi,AsciiNum ;Point to temp location for ASCII number call Int2Ascii ;Convert the integer to ascii lea esi,AsciiNum ;Point to the temp ascii number call PrintString ; and go print it popfd ;Restore the registers popad ; ret ;Return to Calling procedure IntResult ENDP Public _main END ;Code segment ends