The MASM Forum Archive 2004 to 2012

General Forums => The Laboratory => Topic started by: hutch-- on June 06, 2005, 04:59:13 AM

Title: Suggestion with MSVCRT code.
Post by: hutch-- on June 06, 2005, 04:59:13 AM
Among our members are many very experienced C programmers who would be highly familiar with the basics of the standard C runtime library that the MSVCRT.DLL covers. I had an idea in mind where there is such a body of expertise available that some out of their own code or stuff they have seen on a regular basis would have some ideas on leveraging this capacity so that more of the cde would be available to programmers writing code in MASM.

Just as an example the demo that Greg wrote also had an algo at the end of it that could easily be tweaked into a "pause" macro for console type applications and there will of course be many other things that can readily be derived from such a large runtime library.

I thought it was worth the effort to float this past the guys who have many years of C experience to see if there were some useful bits and pieces that could be made into macros for MASM.

PS : One concession, PLEASE put your name on any pieces of genius so we all know who wrote it.
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 09, 2005, 07:00:30 AM
Here is the first piece of genius.  :dazzled:

Its a console macro to emulate the dos "pause".


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

  pause MACRO user_text:VARARG
    ;; -------------------------------------
    ;; display user defined text or default
    ;; text if there is no user defined text
    ;; -------------------------------------
    IFNB <user_text>
      print user_text                           ;; user defined text
    ELSE
      print "Press any key to continue ..."     ;; default text
    ENDIF

    invoke crt__getch                           ;; wait for key

    ;; ----------------------------------------------
    ;; place cursor on next line after key is pressed
    ;; ----------------------------------------------
    print chr$(13,10)
  ENDM

    .data
      tst db "This is a test",0

    .code

start:
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call main

    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc

    pause

    pause "Pause with user defined text message"

    ret

main endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start


LATER :

Slight change to the macro.

LATER AGAIN :

Here are two more.


    env$ MACRO item
      fn crt_getenv,item
      EXITM <eax>
    ENDM

    setenv MACRO value    ; set environment in current thread
      fn crt__putenv,value
    ENDM


They are used as follows.


    setenv "link=\masm32\bin\"

    mov penv, env$("link")
    .if penv != 0
      print penv,13,10
    .endif
Title: Re: Suggestion with MSVCRT code.
Post by: MichaelW on June 10, 2005, 07:15:49 AM
Here are three macros and a test app. For some reason, even though printf outputs to STDOUT, the output cannot be redirected to a file. For the printfr macro it would have been better to use _scprintf instead of a fixed size buffer, but the function apparently is not included in MSVCRT.DLL. A single call to _getch will not pause under all conditions. If the user presses an extended key two (or more?) characters will be placed in the buffer, and the next call will not wait. I added code to flush the buffer a second time just to ensure it would be left empty.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc

    ; ---------------------------------------
    ; The output for this version cannot be
    ; redirected to a file.
    ; ---------------------------------------
    printf MACRO format:REQ,args:VARARG
      IFNB <args>
        invoke crt_printf,reparg(format),args
      ELSE
        invoke crt_printf,reparg(format)
      ENDIF
    ENDM

    ; ------------------------------------
    ; The output for this version can be
    ; redirected to a file.
    ; ------------------------------------
    printfr MACRO format:REQ,args:VARARG
      push  ebx
      mov   ebx,alloc$(256)
      IFNB <args>
        invoke crt__snprintf,ebx,256,reparg(format),args
      ELSE
        invoke crt__snprintf,ebx,256,reparg(format)
      ENDIF
      print ebx
      free$(ebx)
      pop   ebx
    ENDM

    ; -------------------------------------------------
    ; Flushes the input buffer, waits for a keystroke,
    ; and flushes the buffer again, leaving it empty.
    ; -------------------------------------------------
    waitkey MACRO
      @@:
        call  crt__kbhit
        or    eax, eax
        jz    @F
        call  crt__getch
        jmp   @B
      @@:
        call  crt__getch
        call  crt__kbhit
        or    eax, eax
        jnz   @B
    ENDM

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
      dbl1 REAL8  1234.56789
      dd1  dd     12345678h
      str1 db     "yada yada",10,0
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    printf ADDR str1
    printf """quoted string""%c", 10
    printf "((<<&>>))'""%%%c", 10
    printf "break this %cline%c", 10, 10
    printf "%xh = %dd%s", dd1, dd1, chr$(10)
    printf "%f%c", dbl1, 10
    printf "%0.2f%c", dbl1, 10
    printf "%0.0f%c", dbl1, 10
    printf "%010.2f%c%c", dbl1, 10, 10
   
    waitkey

    printfr ADDR str1
    printfr """quoted string""%c", 10
    printfr "((<<&>>))'""%%%c", 10
    printfr "break this %cline%c", 10, 10
    printfr "%xh = %dd%s", dd1, dd1, chr$(10)
    printfr "%f%c", dbl1, 10
    printfr "%0.2f%c", dbl1, 10
    printfr "%0.0f%c", dbl1, 10
    printfr "%010.2f%c", dbl1, 10

    waitkey

    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start


Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 10, 2005, 11:32:06 AM
Michael,

Thanks for the waitkey macro, I had tested the first one on single characters and and in conjunction with 1 key like ALT or CTRL but not in pairs. This one does the job fine. I just added your macro into the "pause" to get the user defined text or default text and it looks like this.

LATER : Tweaked to handle "pause NULL"


  pause MACRO user_text:VARARG
    IFDIF <user_text>,<NULL>                    ;; if user text not "NULL"
      IFNB <user_text>
        print user_text                         ;; user defined text
      ELSE
        print "Press any key to continue ..."   ;; default text
      ENDIF
    ENDIF
    ;; -------------------------------------
    ;; display user defined text or default
    ;; text if there is no user defined text
    ;; -------------------------------------
    @@:
      call  crt__kbhit
      or    eax, eax
      jz    @F
      call  crt__getch
      jmp   @B
    @@:
      call  crt__getch
      call  crt__kbhit
      or    eax, eax
      jnz   @B
    ;; ----------------------------------------------
    ;; place cursor on next line after key is pressed
    ;; ----------------------------------------------
    print chr$(13,10)
  ENDM

Title: Re: Suggestion with MSVCRT code.
Post by: GregL on June 10, 2005, 07:27:10 PM
I am not good at writing macros but I would write it like this:


pause MACRO user_text:VARARG
    IFDIF <user_text>,<NULL>                    ;; if user text not "NULL"
      IFNB <user_text>
        print chr$(13,10)
        print user_text                         ;; user defined text
      ELSE
        print chr$(13,10)
        print "Press any key to continue ..."   ;; default text
      ENDIF
    ENDIF
    ;; -------------------------------------
    ;; display user defined text or default
    ;; text if there is no user defined text
    ;; -------------------------------------
    call crt__getch                   ; regular keys return just a key code
    .if eax == 0 || eax == 0E0h       ; extended keys return 0 plus a key code
                                      ; numeric pad keys return 0E0h plus a key code
        call  crt__getch              ; another call is needed for the key code                           
    .endif   
    ;; ----------------------------------------------
    ;; place cursor on next line after key is pressed
    ;; ----------------------------------------------
    print chr$(13,10)
ENDM


Regular keys return just a key code. Extended keys return 0 plus a key code. Extended keys on the numeric pad return 0E0h plus a key code.

_getch reference on MSDN (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__getch.2c_._getche.asp)

Note: I am using ML.EXE v6.15 and it doesn't like 'pause'. I can't find a reference to that instruction.  If I change it to 'waitkey' no problem.

pause.asm(58) : error A2085: instruction or register not accepted in current CPU mode

Title: Re: Suggestion with MSVCRT code.
Post by: MichaelW on June 11, 2005, 12:31:49 AM
Greg,

I was trying to ensure that the buffer would always be emptied, so later inputs (of any sort) could not be affected. On my Windows 2000 system, with a US keyboard, _getch seems to always return no more than two characters, but can the function be depended on to behave the same for all systems/keyboards?

This is a test app to check the number of characters returned, and to perform a test of both methods to determine how reliably they will empty the buffer. Neither method is completely reliable under heavy system loads.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

  L1:
    call  crt__kbhit
    or    eax, eax
    jz    @F
    call  crt__getch
    jmp   L1
  @@:
    call  crt__getch
    .if eax == 27
        print chr$(13,10)
        jmp   @F
    .endif
    push  eax
    print uhex$(eax),32
    pop   eax
    call  crt__kbhit
    or    eax, eax
    jnz   @B
    print chr$(13,10)
    call  crt__kbhit
    or    eax, eax
    jz    L1
    call  crt__getch
    print uhex$(eax)
    print chr$("<-- left in buffer"),13,10
    jmp   L1

  @@:
    call crt__getch
    .if eax == 27
        exit
    .endif
    push  eax
    print uhex$(eax),32
    pop   eax
    .if eax == 0 || eax == 0E0h
        call  crt__getch
        push  eax
        print uhex$(eax)
        pop   eax
    .endif
    print chr$(13,10)
    call  crt__kbhit
    or    eax, eax
    jz    @B
    call  crt__getch
    print uhex$(eax)
    print chr$("<-- left in buffer"),13,10
    jmp   @B

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 11, 2005, 02:31:46 AM
Damn,

I get the same problem with the name "pause" on ML 7.00 as well. I was trying to retain the DOS name so it would be familiar. Thanks for the MSDN link Greg, the code you posted makes sense in that context.

I am interested in Michael's comment of what constitutes a heavy load as far as a keyboard buffer goes that would effect the reliability of the function.
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on June 11, 2005, 03:21:19 AM
MichaelW,

I would say yes, _getch will always return no more than two characters.

I ran your program, either method works equally well, and yours does flush the keyboard buffer before waiting for a keystroke. I was thinking of using fllush(stdin) to clear the keyboard buffer before waiting for a keystroke. C purists will howl at fflush(stdin) as it is not standard C, but MSVC (and Pelle's C) supports it, so I have no problem using it. I imagine it just calls FlushConsoleInputBuffer but I'm not sure. 

Your method is probably faster than using fflush(stdin).

I just wanted to point out the need to test for 0E0h, but with your method you don't need to test for it. Again, I didn't thoroughly examine your code before opening my mouth.  :bg

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 11, 2005, 04:30:38 AM
Here is another try, it looks like it works OK but is no improvement on either of the ones posted. Two API based macros as well.


    wait_key MACRO
      LOCAL label
      label:
        fn Sleep,10
        call crt__kbhit
        test eax, eax
        jz label
        print chr$(13,10)
        invoke FlushConsoleInputBuffer,rv(GetStdHandle,STD_INPUT_HANDLE)
    ENDM

    date$ MACRO
      IFNDEF @_@_current_local_date_@_@
        .data?
          @_@_current_local_date_@_@ db 128 dup (?)
        .code
      ENDIF
      invoke GetDateFormat,LOCALE_USER_DEFAULT,DATE_LONGDATE,
                           NULL,NULL,ADDR @_@_current_local_date_@_@,128
      EXITM <OFFSET @_@_current_local_date_@_@>
    ENDM

    time$ MACRO
      IFNDEF @_@_current_local_time_@_@
        .data?
          @_@_current_local_time_@_@ db 128 dup (?)
        .code
      ENDIF
      invoke GetTimeFormat,LOCALE_USER_DEFAULT,NULL,NULL,NULL,
                           ADDR @_@_current_local_time_@_@,128
      EXITM <OFFSET @_@_current_local_time_@_@>
    ENDM
Title: Re: Suggestion with MSVCRT code.
Post by: MichaelW on June 11, 2005, 04:58:10 AM
Hutch,

To get a heavy load on my system, all I have to do is start the programming environment for any of the Microsoft Quick languages, including QBasic. When I do so the CPU time for the System Idle Process drops to 0%, a ntvdm.exe task appears with a CPU time of 98-99%, and everything visibly slows down. If I then run the app from my last post and type on the keyboard at a moderate rate, at random intervals one or more keystrokes will be left in the buffer. This is with a P3-500; a faster processor may reduce or eliminate the problem.

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 11, 2005, 05:24:13 AM
Michael,

Thanks, I think I understand what is happening there.

Here is the current test piece, with "pause" being a reserve word in later MASM versions I opted for the traditional basic "inkey" and moved the code for the operation into a procedure as there is no point inlining it as it is hardly speed critical.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    date$ MACRO
      IFNDEF @_@_current_local_date_@_@
        .data?
          @_@_current_local_date_@_@ db 128 dup (?)
        .code
      ENDIF
      invoke GetDateFormat,LOCALE_USER_DEFAULT,DATE_LONGDATE,
                           NULL,NULL,ADDR @_@_current_local_date_@_@,128
      EXITM <OFFSET @_@_current_local_date_@_@>
    ENDM

    time$ MACRO
      IFNDEF @_@_current_local_time_@_@
        .data?
          @_@_current_local_time_@_@ db 128 dup (?)
        .code
      ENDIF
      invoke GetTimeFormat,LOCALE_USER_DEFAULT,NULL,NULL,NULL,
                           ADDR @_@_current_local_time_@_@,128
      EXITM <OFFSET @_@_current_local_time_@_@>
    ENDM

    ;; ----------------------------------
    ;; display user defined text, default
    ;; text or none if NULL is specified.
    ;; ----------------------------------
    inkey MACRO user_text:VARARG
      LOCAL label
      IFDIF <user_text>,<NULL>                  ;; if user text not "NULL"
        IFNB <user_text>
          print user_text                       ;; print user defined text
        ELSE
          print "Press any key to continue ..." ;; print default text
        ENDIF
      ENDIF
      call wait_key
      print chr$(13,10)
    ENDM

    env$ MACRO item
      fn crt_getenv,item
      EXITM <eax>
    ENDM

    setenv MACRO value
      fn crt__putenv,value
    ENDM

    .code

start:
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call main

    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc

    LOCAL penv  :DWORD

    fn SetConsoleTitle,"Ain't MASM beautiful ?"

    print "Today's date is "
    print date$(),13,10,13,10
    print "You started this program at "
    print time$(),13,10

    setenv "link=\masm32\bin\"

    mov penv, env$("link")
    .if penv != 0
      print penv,13,10
    .endif

    inkey NULL

    inkey

    inkey "Pause with user defined text message"

    ret

main endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

wait_key proc

  @@:
    invoke Sleep,10
    call crt__kbhit
    test eax, eax
    jz @B

    invoke FlushConsoleInputBuffer,rv(GetStdHandle,STD_INPUT_HANDLE)

    ret

wait_key endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start
Title: Re: Suggestion with MSVCRT code.
Post by: Jibz on June 11, 2005, 08:37:15 AM
hutch--,

What is it with you and idle loops? :green
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 11, 2005, 08:59:46 AM
 :bg

Old habits die hard but on the bright side, I may add a keystroke escape to a shell proc using the technique.

LATER :

This is the Microsoft code from thier MSDN site on how to use the function, I seriously think mine is better.


// crt_kbhit.c
// compile with: /c
/* This program loops until the user
* presses a key. If _kbhit returns nonzero, a
* keystroke is waiting in the buffer. The program
* can call _getch or _getche to get the keystroke.
*/

#include <conio.h>
#include <stdio.h>

int main( void )
{
   /* Display message until key is pressed. */
   while( !_kbhit() )
      _cputs( "Hit me!! " );

   /* Use _getch to throw key away. */
   printf( "\nKey struck was '%c'\n", _getch() );
}
Title: Re: Suggestion with MSVCRT code.
Post by: Jibz on June 11, 2005, 01:49:20 PM
That doesn't look much like an example to follow :bg.

Here is a function I've used a couple of times -- it uses WaitForSingObject to do an efficient wait, as mentioned on the MSDN page about Low-Level Console Input Functions (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/low_level_console_input_functions.asp):

void waitforkeypress()
{
    HANDLE hin;
    DWORD dwNumEvents, dwNumRead;
    INPUT_RECORD ir;

    /* get standard input handle */
    hin = GetStdHandle(STD_INPUT_HANDLE);

    if (hin == INVALID_HANDLE_VALUE) return;

    /* flush input buffer */
    FlushConsoleInputBuffer(hin);

    /* wait loop */
    while (1)
    {
        /* wait for an input event */
        WaitForSingleObject(hin, INFINITE);

        /* get number of events */
        if (GetNumberOfConsoleInputEvents(hin, &dwNumEvents) && dwNumEvents)
        {
            /* loop through events */
            while (dwNumEvents--)
            {
                /* read event */
                if (ReadConsoleInput(hin, &ir, 1, &dwNumRead) && dwNumRead)
                {
                    /* if it's a key being released, return */
                    if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown == 0) return;
                }
            }
        }
    }
}
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 11, 2005, 02:26:46 PM
Jibz,

It certainly looks a lot better than the MSDN version. There is a tool  have taken a liking to from sysinternals, its called Process Explorer and it tells you some interesting stuff, system idle process sits there taking a bit over 90%, the balance is interrupts and the sum total of the rest are too small to measure so they show 0%. Start up the polling loop as per above and the numbers remain the same, it sits there not consuming enough processor time to register above 0%.

Run something processor intensive that is continuously taking processor time and it takes it from the system idle process.

This is why I have no problems with idle loops as they perform well.
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 12, 2005, 02:05:23 AM
Just as a later thought, I am yet to understand the prejudice against polling loops, they are like anything else, write them properly and they work fine, do it wrong and they will almost lock a box up. Over time I have heard many fashions in programming, you should not use GOTO in a program but should use structured loops. You should not use GLOBAL scope variables but always use LOCALS passed on the stack.

The problem is there is a whole mountain of code that you cannot write if you have restrictions on such techniques. Now in response the the GOTO boogie, I instead only use JUMPS and as few as I can get away with and I simply ignore the "rule" on LOCALS only if I need the scope of a GLOBAL so I wonder if there is a new rule of fashion on using polling loops ?

The basic mechanics is there is no other way of performing regular interval checks on events that test for a result. You can pass this off to the operating system if you like but it still must do the same to determine the results of events. On the win2k and later OS versions this is the 7 to 8% at idle processor usage of interrupts so I don't see that it is all that efficient in terms of processor usage. While I see that Windows is poorly designed in terms of low level access, this type of loop is trivial to write from ring3 access and they test up fine if they are written properly.
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 12, 2005, 04:27:33 AM
This is the latest version of the test piece, added title bar text control for a console using standard API functions. The wait_key procedure needs to be added to the masm32 library.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    date$ MACRO
      IFNDEF @_@_current_local_date_@_@
        .data?
          @_@_current_local_date_@_@ db 128 dup (?)
        .code
      ENDIF
      invoke GetDateFormat,LOCALE_USER_DEFAULT,DATE_LONGDATE,
                           NULL,NULL,ADDR @_@_current_local_date_@_@,128
      EXITM <OFFSET @_@_current_local_date_@_@>
    ENDM

    time$ MACRO
      IFNDEF @_@_current_local_time_@_@
        .data?
          @_@_current_local_time_@_@ db 128 dup (?)
        .code
      ENDIF
      invoke GetTimeFormat,LOCALE_USER_DEFAULT,NULL,NULL,NULL,
                           ADDR @_@_current_local_time_@_@,128
      EXITM <OFFSET @_@_current_local_time_@_@>
    ENDM

    ;; ----------------------------------
    ;; display user defined text, default
    ;; text or none if NULL is specified.
    ;; ----------------------------------
    inkey MACRO user_text:VARARG
      IFDIF <user_text>,<NULL>                  ;; if user text not "NULL"
        IFNB <user_text>
          print user_text                       ;; print user defined text
        ELSE
          print "Press any key to continue ..." ;; print default text
        ENDIF
      ENDIF
      call wait_key
      print chr$(13,10)
    ENDM

    SetConsoleCaption MACRO title_text
      invoke SetConsoleTitle,reparg(title_text)
    ENDM

    GetConsoleCaption$ MACRO
      IFNDEF @@_console_caption_buffer_@@
      .data?
        @@_console_caption_buffer_@@ db 260 dup (?)
      .code
      ENDIF
      invoke GetConsoleTitle,ADDR @@_console_caption_buffer_@@,260
      EXITM <OFFSET @@_console_caption_buffer_@@>
    ENDM

    env$ MACRO item
      fn crt_getenv,item
      EXITM <eax>
    ENDM

    setenv MACRO value
      fn crt__putenv,value
    ENDM

    .code

start:
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call main

    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc

    LOCAL penv  :DWORD

    SetConsoleCaption "Ain't MASM beautiful ?"

    print "Today's date is "
    print date$(),13,10,13,10
    print "You started this program at "
    print time$(),13,10,13,10

    print "The console caption is '"
    print GetConsoleCaption$(),"'",13,10

    setenv "link=\masm32\bin\"

    mov penv, env$("link")
    .if penv != 0
      print penv,13,10
    .endif

    inkey NULL

    inkey

    inkey "Wait for keyboard input with user defined text ",62," "

    ret

main endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

wait_key proc

  @@:
    invoke Sleep,10
    call crt__kbhit
    test eax, eax
    jz @B

    invoke FlushConsoleInputBuffer,rv(GetStdHandle,STD_INPUT_HANDLE)

    ret

wait_key endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on June 12, 2005, 04:32:02 AM
Hutch,

I tried out the latest macros, they look good to me. I watched the CPU Usage when 'wait_key' is looping and it is essentially zero.

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 12, 2005, 04:47:06 AM
Greg,

Thansk for giving it a blast, I don't think it works any better than either yours or Michaels but its smaller and simpler. It makes more sense to put it in a library module than inline it as its hardly speed critical and just let the macro handle the string options. I think your suggestion to use FlushConsoleInputBuffer() was a good idea as it did simplify the code.
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 13, 2005, 03:12:57 AM
Here is a freestyle variation of the wait_key proc, it automatically counts down from 10 seconds to zero and exits if a key has not been pressed while updating the console window title. It could probably do with some tidying up but it seems to work OK.

LATER : Tidied up a bit.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

wait_key proc

    LOCAL tc    :DWORD
    LOCAL cnt   :DWORD
    LOCAL buf   :DWORD
    LOCAL buffer[32]:BYTE

    mov tc, rv(GetTickCount)
    add tc, 1000
    mov cnt, 10

    jmp ifin

  @@:
    invoke Sleep,10
    .if rv(GetTickCount) >= tc
      add tc, 1000
      sub cnt, 1
      jz @F
    ifin:
      mov buf, ptr$(buffer)
      SetConsoleCaption cat$(buf,str$(cnt)," seconds left")
    .endif
    test rv(crt__kbhit), eax
    jz @B
  @@:

    invoke FlushConsoleInputBuffer,rv(GetStdHandle,STD_INPUT_HANDLE)

    ret

wait_key endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
Title: Re: Suggestion with MSVCRT code.
Post by: Mark Jones on June 14, 2005, 07:03:59 PM
Are we adding all these tasty little tidbidts to SP3? :bg
Title: Re: Suggestion with MSVCRT code.
Post by: zooba on June 15, 2005, 12:31:56 AM
Here's my suggestion for a pause/wait_key function. It doesn't use the function from the C runtime (which I had to avoid because I couldn't find an include/library for it :eek) but I think it's just as neat:

wait_key PROC
    LOCAL   hConsole:DWORD
    LOCAL   dwConsoleMode:DWORD
   
    invoke  GetStdHandle, STD_INPUT_HANDLE
    mov     hConsole, eax
   
    invoke  GetConsoleMode, hConsole, ADDR dwConsoleMode
    invoke  SetConsoleMode, hConsole, 0
    invoke  ReadFile, hConsole, NULL, 1, NULL, NULL
    invoke  SetConsoleMode, hConsole, dwConsoleMode

    invoke  FlushConsoleInputBuffer, hConsole
    ret
wait_key ENDP


The local variables could probably be avoided by using push/pops or registers, but either way its going to use the stack so I decided to go with the easiest to read. And as hutch (I think) mentioned earlier, it's hardly time critical code and when you play with APIs optimization goes out the MS Windows anyway  :bg :cheekygreen:
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 15, 2005, 12:38:13 AM
zooba,

Thanks for this piece of genius, it works fine, handles the combined keys correctly and has very low processor usage.  :U
Title: Re: Suggestion with MSVCRT code.
Post by: Jibz on June 15, 2005, 09:01:23 AM
None of the 'special' keys (like CTRL, ALT, SHIFT, ESC, arrow keys, F-keys, etc.) seem to work with that version?

Edit: I just noticed that CTRL, ALT and SHIFT did not seem to work with the polling loop version either.

Edit 2: Of course those three don't work with the 'pause' command either, so it's not a big problem unless you're the type who takes "Press any key to continue..." very literally :toothy.
Title: Re: Suggestion with MSVCRT code.
Post by: MazeGen on June 15, 2005, 11:39:49 AM
Quote from: Greg on June 10, 2005, 07:27:10 PM
Note: I am using ML.EXE v6.15 and it doesn't like 'pause'. I can't find a reference to that instruction.  If I change it to 'waitkey' no problem.

pause.asm(58) : error A2085: instruction or register not accepted in current CPU mode


PAUSE is new since Pentium4, but is backward compatible with all IA-32 processors, because its opcode corresponds to REP NOP instruction.
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on June 16, 2005, 01:27:47 AM
zooba,

  Nice code :U,  that works better than the Win32 API version of "waitkey" I had.

MazeGen,

  Thanks for the info, I never found anything on the PAUSE instruction and gave up.

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 16, 2005, 02:51:01 AM
 :bg

> Edit: I just noticed that CTRL, ALT and SHIFT did not seem to work with the polling loop version either.

But look on the bright side, it would be easy enough to add URL checking, DRM testing and with just a bit more work, multimedia support. Imagine having music while you made up your mind which key to press. We could usher in a new era of user interaction at the console level that may see the BIG return to true console apps.  :toothy
Title: Re: Suggestion with MSVCRT code.
Post by: Tedd on June 16, 2005, 10:49:22 AM
Please excuse Hutch, he's been 'testing' his homebrew again :lol
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 16, 2005, 12:03:47 PM
Nah,

My code is unlicenced as GPA, Glenfiddich Powered Assembler.
Title: Re: Suggestion with MSVCRT code.
Post by: MichaelW on June 17, 2005, 05:13:57 AM
Hutch,

I see a potential problem with your latest waitkey procedure. If the user presses a key at some point before waitkey is called, it will not wait. While some users might expect a key pressed ahead of time to have an effect, I think most users would not.
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 17, 2005, 07:33:55 AM
Yes,

Its a good point, if it tests up as a problem, it would require the FlushConsoleInputBuffer() API call to be made both before and after to be safe.

LATER :

I changed the test piece with a Sleep,3000 and pressed a key a number of times and it allowed the first following wait_key procedure to fall through so adding the extra API call seems to fix that potential problem fine.  This is the proc with the added API call.


wait_key proc

    LOCAL hConsole  :DWORD

    mov hConsole, rv(GetStdHandle,STD_INPUT_HANDLE)

    invoke FlushConsoleInputBuffer,hConsole

  @@:
    invoke Sleep,10
    call crt__kbhit
    test eax, eax
    jz @B

    invoke FlushConsoleInputBuffer,hConsole

    ret

wait_key ENDP


Damn, all this incredible bloat.  :bg
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 20, 2005, 12:57:40 PM
I have been playing with the idea of a proc that returns the scancode of the key pressed but I cannot improve on a slight modification of Greg's version. This is what it looks like. About the only complaint is it returns garbage with the F keys.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    .code

start:
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call main

    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc

    LOCAL var   :DWORD
    LOCAL pinp  :DWORD              ; pointer for input buffer
    LOCAL inbuffer[8]:BYTE          ; input buffer

    mov pinp, ptr$(inbuffer)

    cls

    print "Press a key to display its ASCII value or ESC to quit",13,10

  backin:
    call ret_key

    mov ecx, pinp
    mov [ecx], al               ; write AL to 1st BYTE of buffer

    .if al != 27                ; if not ESC
      push eax
      print pinp," = "
      pop eax
      print str$(eax),13,10
      jmp backin
    .endif

    ret

main endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

ret_key proc

    invoke FlushConsoleInputBuffer,rv(GetStdHandle,STD_INPUT_HANDLE)

    call crt__getch
    test eax, eax
    jz @F
    cmp eax, 0E0h
    jnz quit
  @@:
    call crt__getch
  quit:
    ret

ret_key endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on June 21, 2005, 02:36:36 AM
Hutch,

It seems to be working correctly on my system.

F1:  ; = 59
F2:  < = 60
F3:  = = 61
F4:  > = 62
F5:  ? = 63
F6:  @ = 64
F7:  A = 65
F8:  B = 66
F9:  C = 67
F10: D = 68
F11: à = 133
F12: å = 134

Later: I should say it's returning the correct scan codes. My F11 and F12 codes are strange though.

Title: Re: Suggestion with MSVCRT code.
Post by: GregL on June 23, 2005, 12:18:59 AM
Hutch,

I took your code and played with it a bit.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include c:\masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    .code

start:
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call main

    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc

    LOCAL acode :DWORD              ; ASCII code
    LOCAL scode :DWORD              ; Scan code
    LOCAL vcode :DWORD              ; Virtual-key code
    LOCAL outbuffer[64]:BYTE
       

    cls

    print "Press a key (ESC to quit): ", 13, 10

  backin:
    call ret_key
    .if al != 27                ; if not ESC
        .if edx == 0
            mov acode, eax
            print SADD("ASCII code = ")
            print hex$(acode)
            print SADD("h, ASCII character  = ")
            mov eax, acode
            mov outbuffer[0], al
            mov outbuffer[1], 0
            print ADDR outbuffer, 13, 10
        .else
            mov scode, eax
            print SADD("Scan code  = ")
            print hex$(scode)
            print chr$("h, Virtual-Key code = ")
            invoke MapVirtualKey, scode, 1
            mov vcode, eax
            print hex$(vcode)
            print chr$("h, Key name = ")
            shl scode, 16
            invoke GetKeyNameText, scode, ADDR outbuffer, SIZEOF outbuffer
            print ADDR outbuffer, 13, 10
        .endif   

        jmp backin
   
    .endif

    ret

main endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
ret_key proc
; returns code in EAX
; EDX is 0 if ASCII, 1 if Scan Code

    invoke FlushConsoleInputBuffer,rv(GetStdHandle,STD_INPUT_HANDLE)
       
    call crt__getch                 ; it's an ASCII Code
    mov edx, 0
    .if (eax == 0) || (eax == 0E0h)
        call crt__getch             ; it's a Scan Code
        mov edx, 1
    .endif
   
    ret

ret_key endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on June 23, 2005, 05:00:53 AM
Thanks Greg, using a register to flag an extended key is a good idea. This is the modded version.


ret_key proc

    invoke FlushConsoleInputBuffer,rv(GetStdHandle,STD_INPUT_HANDLE)

    call crt__getch
    xor ecx, ecx
    test eax, eax
    jz @F
    cmp eax, 0E0h
    jnz quit
  @@:
    call crt__getch
    mov ecx, 1
  quit:
    ret

ret_key endp
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on June 24, 2005, 04:30:43 AM
Zooba,

Quote from: GregNice code  :U,  that works better than the Win32 API version of "waitkey" I had.

Well, it's not perfect, your 'wait_key' procedure doesn't accept extended (non-ASCII) keys. I know, I'm being picky.  :bg



Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 06, 2005, 03:31:34 AM
Some 'number to string' conversion procedures that use the sprintf CRT function.


; Greg Lyon · 2005
.586
.MODEL FLAT, stdcall
option casemap:none

include windows.inc

include kernel32.inc
include user32.inc
include masm32.inc
include msvcrt.inc

include c:\masm32\macros\macros.asm

includelib kernel32.lib
includelib user32.lib
includelib masm32.lib
includelib msvcrt.lib

ByToStr   PROTO byValue  :BYTE,   lpBuffer:PTR BYTE
SbyToStr  PROTO sbyValue :SBYTE,  lpBuffer:PTR BYTE
WdToStr   PROTO wdValue  :WORD,   lpBuffer:PTR BYTE
SwdToStr  PROTO swdValue :SWORD,  lpBuffer:PTR BYTE
DwToStr   PROTO dwValue  :DWORD,  lpBuffer:PTR BYTE
SdwToStr  PROTO sdwValue :SDWORD, lpBuffer:PTR BYTE
QwToStr   PROTO qwValue  :QWORD,  lpBuffer:PTR BYTE
SqwToStr  PROTO sqwValue :QWORD,  lpBuffer:PTR BYTE
FltToStr  PROTO fltValue :REAL4,  lpBuffer:PTR BYTE
DblToStr  PROTO dblValue :REAL8,  lpBuffer:PTR BYTE
LdblToStr PROTO ldblValue:REAL10, lpBuffer:PTR BYTE
WaitKey   PROTO

.CONST

    byTest    BYTE   0FFh
    sbyTest   SBYTE  0FFh
    wdTest    WORD   0FFFFh
    swdTest   SWORD  0FFFFh
    dwTest    DWORD  0FFFFFFFFh
    sdwTest   SDWORD 0FFFFFFFFh
    qwTest    QWORD  0FFFFFFFFFFFFFFFFh
    sqwTest   QWORD  0FFFFFFFFFFFFFFFFh
    fltTest   REAL4  123.4567890
    dblTest   REAL8  456.7890123
    ldblTest  REAL10 789.0123456
   
.DATA

    szBuffer  BYTE  96 dup(0)
    pszBuffer PBYTE szBuffer

.CODE

start:

    invoke ByToStr, byTest, pszBuffer
    invoke crt_puts, pszBuffer
       
    invoke SbyToStr, sbyTest, pszBuffer
    invoke crt_puts, pszBuffer

    invoke WdToStr, wdTest, pszBuffer
    invoke crt_puts, pszBuffer
   
    invoke SwdToStr, swdTest, pszBuffer
    invoke crt_puts, pszBuffer

    invoke DwToStr, dwTest, pszBuffer
    invoke crt_puts, pszBuffer
           
    invoke SdwToStr, sdwTest, pszBuffer
    invoke crt_puts, pszBuffer

    invoke QwToStr, qwTest, pszBuffer
    invoke crt_puts, pszBuffer
   
    invoke SqwToStr, sqwTest, pszBuffer
    invoke crt_puts, pszBuffer
   
    invoke FltToStr, fltTest, pszBuffer
    invoke crt_puts, pszBuffer
   
    invoke DblToStr, dblTest, pszBuffer
    invoke crt_puts, pszBuffer
   
    invoke LdblToStr, ldblTest, pszBuffer
    invoke crt_puts, pszBuffer
   
    call WaitKey
   
    invoke ExitProcess, 0
     
;======================================================
ByToStr PROC byValue:BYTE, lpBuffer:PTR BYTE
    ; byValue is considered unsigned
    invoke crt_sprintf, lpBuffer, SADD("%u"), byValue
    ret
ByToStr ENDP   
;======================================================
SbyToStr PROC sbyValue:SBYTE, lpBuffer:PTR BYTE
    ; sbyValue is considered signed
    invoke crt_sprintf, lpBuffer, SADD("%d"), sbyValue
    ret
SbyToStr ENDP         
;======================================================
WdToStr PROC wdValue:WORD, lpBuffer:PTR BYTE
    ; wdValue is considered unsigned
    invoke crt_sprintf, lpBuffer, SADD("%hu"), wdValue
    ret
WdToStr ENDP   
;======================================================
SwdToStr PROC swdValue:SWORD, lpBuffer:PTR BYTE
    ; swdValue is considered signed
    invoke crt_sprintf, lpBuffer, SADD("%hd"), swdValue
    ret
SwdToStr ENDP         
;======================================================
DwToStr PROC dwValue:DWORD, lpBuffer:PTR BYTE
    ; dwValue is considered unsigned
    invoke crt_sprintf, lpBuffer, SADD("%lu"), dwValue
    ret
DwToStr ENDP   
;======================================================
SdwToStr PROC sdwValue:SDWORD, lpBuffer:PTR BYTE
    ; sdwValue is considered signed
    invoke crt_sprintf, lpBuffer, SADD("%ld"), sdwValue
    ret
SdwToStr ENDP   
;======================================================
QwToStr PROC qwValue:QWORD, lpBuffer:PTR BYTE
    ; qwValue is considered unsigned
    invoke crt_sprintf, lpBuffer, SADD("%I64u"), qwValue
    ret
QwToStr ENDP
;======================================================
SqwToStr PROC sqwValue:QWORD, lpBuffer:PTR BYTE
    ; sqwValue is considered signed
    invoke crt_sprintf, lpBuffer, SADD("%I64d"), sqwValue
    ret
SqwToStr ENDP
;======================================================
FltToStr PROC fltValue:REAL4, lpBuffer:PTR BYTE
    ; REAL4 must be converted to REAL8 for sprintf
    LOCAL dblValue:REAL8
    finit
    fld fltValue
    fstp dblValue
    fwait
    invoke crt_sprintf, lpBuffer, SADD("%lf"), dblValue
    ret
FltToStr ENDP
;======================================================
DblToStr PROC dblValue:REAL8, lpBuffer:PTR BYTE
    invoke crt_sprintf, lpBuffer, SADD("%lf"), dblValue
    ret
DblToStr ENDP
;======================================================
LdblToStr PROC ldblValue:REAL10, lpBuffer:PTR BYTE
    ; REAL10 must be converted to REAL8 for sprintf
    ; A 'long double' in MS C/C++ is a REAL8
    LOCAL dblValue:REAL8
    finit
    fld ldblValue
    fstp dblValue
    fwait
    invoke crt_sprintf, lpBuffer, SADD("%lf"), dblValue
    ret
LdblToStr ENDP
;======================================================
WaitKey PROC
    invoke crt_printf, SADD(13,10,"Press any key to continue...")
    invoke crt__getch
    .if (eax == 0) || (eax == 0E0h)
        invoke crt__getch
    .endif
    invoke crt_printf, SADD(13,10)
    ret
WaitKey ENDP   
;======================================================
END start

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 06, 2005, 03:48:16 AM
Thanks Greg,

This is great stuff and very useful.  :U
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 06, 2005, 04:22:54 AM
Hutch,

You know, using the Pelle's C run-time library would have some advantages over the MSVC run-time library as Pelle's C supports most, if not all, of the new C99 functions and MSVC does not support them at all. There are several new and very useful C99 functions that could be used in MASM32.

I wonder if that would be OK with Pelle?


Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 06, 2005, 04:44:55 AM
Greg,

Let me try this out on you, the set of functions are very good as they make a very good range of functionality available but there is no good reason to place tem in a seperate procedure when almost all of them make a direct call to MSVCRT.DLL. What I think would be more useful as we already have the C runtime functions available would be to make a set of direct macros using this excellent range of functionality so they could be used in a closer to "function" format with return values much like a higher level language.

Its basically the idea that we have the preprocessor available so we may as well make use of it.

Now another question as you have the expertise in C runtime library functions, are the versions using the "sprintf" function as fast as the dedicated conversions in msvcrt like _ltoa or similar ?
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 06, 2005, 05:54:22 AM
Hutch,

Yeah, I know, macros would be better. I thought about writing these procedures as macros, but I'm lousy at macros. I guess I need to get better at them. I'm just passing along ideas.

As far as the speed compared to ltoa etc., I don't know, I would have to do some testing. I do know the floating-point conversion functions like fcvt are pretty lousy because they don't store the decimal point in the string, you would need an additional routine to insert the decimal point into the string. itoa and ltoa are fine.

I've never been greatly concerned about speed unless it's really needed in the routine. I'm more interested in the functionality, simplicity and elegance of the code.

I do need to learn how to write macros better ...


 
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 06, 2005, 06:25:13 AM
Greg,

See what you think of these, I have not put them in a test piece but I think they are OK.


;; ----------------------------------------------
  byte$ MACRO bytevalue
    LOCAL buffer
    .data?
      buffer db 4 dup (?)
    .code
    fn crt_sprintf,OFFSET Buffer,"%u",bytevalue
    EXITM <OFFSET buffer>
  ENDM
;; ----------------------------------------------
  sbyte$ MACRO bytevalue
    LOCAL buffer
    .data?
      buffer db 4 dup (?)
    .code
    fn crt_sprintf,OFFSET Buffer,"%d",bytevalue
    EXITM <OFFSET buffer>
  ENDM
;; ----------------------------------------------
Title: Re: Suggestion with MSVCRT code.
Post by: Vortex on July 06, 2005, 08:01:24 AM
 :P
Here is my C run-time example :

.386
.model flat,stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include  crtdll.inc
includelib \masm32\lib\kernel32.lib
includelib  crtdll.lib

.data
msg db "Command=%s P1=%s P2=%s",0
errmsg db "Only two parameters!",0

.data?
argc dd ?
argv dd ?
env dd ?
.code
start:
invoke __GetMainArgs,ADDR argc,ADDR argv,ADDR env,0
cmp argc,3
jne error
mov edx,argv
invoke printf,ADDR msg,dword ptr [edx],dword ptr [edx+4],dword ptr [edx+8]
finish:
invoke ExitProcess,0
error:
invoke printf,ADDR errmsg
jmp finish

END start

[attachment deleted by admin]
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 06, 2005, 08:18:11 AM
Looks good Erol.  :U
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 07, 2005, 01:22:17 AM
'Number to string' macros that use the C Run-time sprintf function. I had nothing but problems using fn or invoke in these macros, I never figured out why, I did it the direct way and it worked. Any suggestions for improvement are welcome.


.586
.MODEL FLAT, stdcall
option casemap:none

include c:\masm32\include\windows.inc

include c:\masm32\include\kernel32.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\masm32.inc
include c:\masm32\include\msvcrt.inc

include c:\masm32\macros\macros.asm

includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\masm32.lib
includelib c:\masm32\lib\msvcrt.lib

;; ----------------------------------------------
ubyte$ MACRO ubytevalue:req
    ; unsigned byte
    LOCAL buffer
    .data?
        buffer BYTE 4 dup(?)
    IFNDEF ubfmt   
    .data   
        ubfmt  BYTE "%hhu", 0
    ENDIF   
    .code
        mov   al, ubytevalue
        movzx eax, al
        push  eax
        push  OFFSET ubfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sbyte$ MACRO sbytevalue:req
    ; signed byte
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF sbfmt     
    .data   
        sbfmt  BYTE "%hhd", 0
    ENDIF   
    .code
        mov   al, sbytevalue
        movsx eax, al
        push  eax
        push  OFFSET sbfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xbyte$ MACRO xbytevalue:req
    ; unsigned hex byte
    LOCAL buffer
    .data?
        buffer BYTE 4 dup(?)
    IFNDEF xbfmt   
    .data   
        xbfmt  BYTE "%hhX", 0
    ENDIF   
    .code
        mov   al, xbytevalue
        movzx eax, al
        push  eax
        push  OFFSET xbfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
uword$ MACRO uwordvalue:req
    ; unsigned word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF uwfmt   
    .data   
        uwfmt  BYTE "%hu", 0
    ENDIF   
    .code
        mov   ax, uwordvalue
        movzx eax, ax
        push  eax
        push  OFFSET uwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sword$ MACRO swordvalue:req
    ; signed word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF swfmt   
    .data   
        swfmt  BYTE "%hd", 0
    ENDIF   
    .code
        mov   ax, swordvalue
        movsx eax, ax
        push  eax
        push  OFFSET swfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xword$ MACRO xwordvalue:req
    ; unsigned hex word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF xwfmt   
    .data   
        xwfmt  BYTE "%hX", 0
    ENDIF   
    .code
        mov   ax, xwordvalue
        movzx eax, ax
        push  eax
        push  OFFSET xwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
udword$ MACRO udwordvalue:req
    ; unsigned dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF udwfmt   
    .data   
        udwfmt BYTE "%lu", 0
    ENDIF   
    .code
        push  udwordvalue
        push  OFFSET udwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sdword$ MACRO sdwordvalue:req
    ; signed dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF sdwfmt   
    .data   
        sdwfmt    BYTE "%ld", 0
    ENDIF   
    .code
        push  sdwordvalue
        push  OFFSET sdwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xdword$ MACRO xdwordvalue:req
    ; unsigned hex dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF xdwfmt   
    .data   
        xdwfmt BYTE "%lX", 0
    ENDIF   
    .code
        push  xdwordvalue
        push  OFFSET xdwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 12
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
uqword$ MACRO uqwordvalue:req
    ; unsigned qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF uqwfmt   
    .data   
        uqwfmt BYTE "%I64u", 0
    ENDIF   
    .code
        push  DWORD PTR [uqwordvalue+4]
        push  DWORD PTR [uqwordvalue+0]
        push  OFFSET uqwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 16
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sqword$ MACRO sqwordvalue:req
    ; signed qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF sqwfmt   
    .data   
        sqwfmt BYTE "%I64d", 0
    ENDIF   
    .code
        push  SDWORD PTR [sqwordvalue+4]
        push  DWORD PTR  [sqwordvalue+0]
        push  OFFSET sqwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 16
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xqword$ MACRO xqwordvalue:req
    ; unsigned hex qword
    LOCAL buffer
    .data?
        buffer BYTE 20 dup(?)
    IFNDEF xqwfmt   
    .data   
        xqwfmt    BYTE "%I64X", 0
    ENDIF   
    .code
        push  DWORD PTR [xqwordvalue+4]
        push  DWORD PTR [xqwordvalue+0]
        push  OFFSET xqwfmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 16
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real4$ MACRO r4value:req
    LOCAL r8value, buffer
    .data?
        r8value REAL8 ?
        buffer  BYTE  52 dup(?)
    IFNDEF r8fmt   
    .data
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        finit
        fld   r4value
        fstp  r8value
        fwait
        push  DWORD PTR [r8value+4]
        push  DWORD PTR [r8value+0]
        push  OFFSET r8fmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 16
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real8$ MACRO r8value:req
    LOCAL buffer
    .data?
        buffer BYTE 320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt  BYTE "%lf", 0
    ENDIF   
    .code
        push  DWORD PTR [r8value+4]
        push  DWORD PTR [r8value+0]
        push  OFFSET r8fmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 16
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real10$ MACRO r10value:req
    LOCAL r8value, buffer
    .data?
        r8value REAL8 ?
        buffer  BYTE  320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        finit
        fld   r10value
        fstp  r8value
        fwait
        push  DWORD PTR [r8value+4]
        push  DWORD PTR [r8value+0]
        push  OFFSET r8fmt
        push  OFFSET buffer
        call  crt_sprintf
        add   esp, 16
    EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
WaitKey MACRO
    LOCAL crlf, pak
    .data
        crlf BYTE 13, 10, 0
        pak  BYTE 13, 10, "Press any key to continue...", 0
    .code   
        push OFFSET pak
        call crt_printf
        add esp, 4
        call crt__getch
        .if (eax == 0) || (eax == 0E0h)
            call crt__getch
        .endif
        push OFFSET crlf
        call crt_printf
        add esp, 4
ENDM
;; ----------------------------------------------

.DATA
       
    ubyMax BYTE   255                        ; UCHAR_MAX
    ubyMin BYTE     0                        ; UCHAR_MIN
   
    sbyMax SBYTE  127                        ; CHAR_MAX
    sbyMin SBYTE -128                        ; CHAR_MIN
   
    uwdMax WORD   65535                      ; USHRT_MAX
    uwdMin WORD       0                      ; USHRT_MIN
   
    swdMax SWORD  32767                      ; SHRT_MAX
    swdMin SWORD -32768                      ; SHRT_MIN
   
    udwMax DWORD   4294967295                ; ULONG MAX
    udwMin DWORD            0                ; ULONG_MIN
   
    sdwMax SDWORD  2147483647                ; LONG_MAX
    sdwMin SDWORD -2147483647 - 1            ; LONG_MIN
   
    uqwMax QWORD 18446744073709551615        ; _UI64_MAX
    uqwMin QWORD                    0        ; _UI64_MIN
   
    sqwMax QWORD  9223372036854775807        ; _I64_MAX
    sqwMin QWORD -9223372036854775807 - 1    ; _I64_MIN
   
    r4Max  REAL4   3.402823466E+38           ; FLT_MAX
    r4Min  REAL4  -1.175494351E-38           ; FLT_MIN
   
    r8Max  REAL8   1.7976931348623158E+308   ; DBL_MAX
    r8Min  REAL8  -2.2250738585072014E-308   ; DBL_MIN
   
    r10Max REAL10  1.7976931348623158E+308   ; LDBL_MAX ( = DBL_MAX)
    r10Min REAL10 -2.2250738585072014E-308   ; LDBL_MIN ( = DBL_MIN)
       
.CODE

start:
       
    invoke crt_puts, ubyte$(ubyMax)
    invoke crt_puts, ubyte$(ubyMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sbyte$(sbyMax)
    invoke crt_puts, sbyte$(sbyMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xbyte$(ubyMax)
    invoke crt_puts, xbyte$(ubyMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, uword$(uwdMax)
    invoke crt_puts, uword$(uwdMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sword$(swdMax)
    invoke crt_puts, sword$(swdMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xword$(uwdMax)
    invoke crt_puts, xword$(uwdMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, udword$(udwMax)
    invoke crt_puts, udword$(udwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sdword$(sdwMax)
    invoke crt_puts, sdword$(sdwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xdword$(udwMax)
    invoke crt_puts, xdword$(udwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, uqword$(uqwMax)
    invoke crt_puts, uqword$(uqwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sqword$(sqwMax)
    invoke crt_puts, sqword$(sqwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xqword$(uqwMax)
    invoke crt_puts, xqword$(uqwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, real4$(r4Max)
    invoke crt_puts, real4$(r4Min)
    invoke crt_puts, SADD(0)
    invoke crt_puts, real8$(r8Max)
    invoke crt_puts, real8$(r8Min)
    invoke crt_puts, SADD(0)
    invoke crt_puts, real10$(r10Max)
    invoke crt_puts, real10$(r10Min)
           
    WaitKey
         
    invoke ExitProcess, 0

end start


Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 07, 2005, 01:26:38 AM
Greg,

These look good and should be a great improvement in the handling of such a wide range of data types. If you are happy enough that they are reliable, I would like to add them to the macros.asm file for MASM32 as I have been doing a lot of work on it recently myself.
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 07, 2005, 01:37:37 AM
Hutch,

You bet. But I haven't done any testing of them besides the program I posted. I made a few corrections a few minutes after I first posted it, cleanup stuff, so get the latest version. Maybe some other folks will try them out.

Any idea why I was having problems using fn and invoke in the macros?

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 07, 2005, 01:47:26 AM
Greg,

I am not sure but I notice that you are zero extending the byte values to DWORD so the invoke syntax may not be handling this correctly. The "fn" macro uses invoke.
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 07, 2005, 02:12:16 AM
Hutch,

Yeah, that's where the problem was, invoke was not handling it correctly. Same thing with some of the other types.

I did it this way so that you would get an assembly error if you passed anything other than the correct type:


    mov   al, bytevalue
    movzx eax, al
    push  eax


instead of


    movzx eax, bytevalue



Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 07, 2005, 03:18:48 AM
Yes,

I got the same results. I played with the first two and you can use invoke with them if you extend the data size to DWORD. Here are the two tested versions. There is no reason to change the manual layout as invoke does not do it any better but I have one suggestion, the format strings only need to be defined once so I put them in an IFNDEF block and reduced the buffer data sizes to the next aligned size after the maximum size that can be written to the data in characters.


ubyte$ MACRO bytevalue:req
  LOCAL buffer
  .data?
    buffer db 4 dup (?)
    IFNDEF ubfmt
    .data
      ubfmt db "%u",0
    ENDIF
  .code
  mov al, bytevalue
  movzx eax, al
  invoke crt_sprintf,OFFSET buffer,OFFSET ubfmt,eax
  EXITM <OFFSET buffer>
ENDM

sbyte$ MACRO bytevalue:req
  LOCAL buffer
  .data?
    buffer db 4 dup (?)
    IFNDEF sbfmt
    .data
      sbfmt db "%d",0
    ENDIF
  .code
  mov al, bytevalue
  movsx eax, al
  invoke crt_sprintf,OFFSET buffer,OFFSET sbfmt,eax
  EXITM <OFFSET buffer>
ENDM
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 07, 2005, 05:02:16 AM
Hutch,

Quote
IFNDEF
good idea

For sbyte$ max bytes is 5 ("-128",0) :bg

tomorrow ...

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 07, 2005, 05:41:12 AM
Yep,

You are right actually, problem is with counting with your fingers is you don't get signed values all that well.  :red
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 07, 2005, 09:48:02 PM
I updated the 'number to string' macros in my earlier post as there were some problems I discovered. The qwords were being pushed incorrectly. I also added the IFNDEF for the format strings, changed the buffer lengths and added some more testing.

I deleted a question that was here because the light just went on, doh! I need to take a break.  ::)
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 08, 2005, 01:31:45 AM
Greg,

These are testing up fine at this end, they look like they are ready to rock 'n roll.
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 08, 2005, 11:17:57 PM
Hutch,

I think so.


Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 10, 2005, 02:00:13 AM
String input using C Run-Time Library fgets function.


.586
.MODEL FLAT, stdcall
option casemap:none

include windows.inc

include kernel32.inc
include user32.inc
;include masm32.inc
include msvcrt.inc

include c:\masm32\macros\macros.asm

includelib kernel32.lib
includelib user32.lib
;includelib masm32.lib
includelib msvcrt.lib

;-----------------------------------------------------
linein MACRO
    LOCAL buffer
    .data?
        buffer BYTE 96 dup(?)
    IFNDEF strFmt   
    .data
        strFmt BYTE "%s", 0
    ENDIF
    IFNDEF Cr
    .data
        dwNewLine DWORD 10
    ENDIF   
    .code   
    invoke crt_fgets, ADDR buffer, SIZEOF buffer, crt__iob
    push eax
    invoke crt_strchr, ADDR buffer, dwNewLine
    .if eax
        mov BYTE PTR [eax], 0   ; remove the newline from buffer
    .endif   
    pop eax
    EXITM <eax>
ENDM   
;-----------------------------------------------------
WaitKey MACRO
    LOCAL crlf, pak
    .data
        szCrLf BYTE 13, 10, 0
        szPAK  BYTE 13, 10, "Press any key to continue...", 0
    .code   
        invoke crt_printf, ADDR szPAK         
        call crt__getch
        .if (eax == 0) || (eax == 0E0h)
            call crt__getch
        .endif
        invoke crt_printf, ADDR szCrLf
ENDM
;-----------------------------------------------------

.DATA

    lpInput DWORD 0
    msg1    BYTE "Enter some text: ", 0
    msg2    BYTE "You entered:     %s", 13, 10, 0

.CODE

start:
   
    invoke crt_printf, ADDR msg1
    mov lpInput, linein()
    invoke crt_printf, ADDR msg2, lpInput
   
    WaitKey
    invoke ExitProcess, 0

end start

Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 11, 2005, 04:09:38 AM
'String to number' procedures using the C Run-Time function sscanf.


; 'String to number' procedures that use
; the C Run-Time Library function sscanf.
; Greg Lyon - 2005
;
.586
.MODEL FLAT, stdcall
option casemap:none

include windows.inc

include kernel32.inc
include user32.inc
include masm32.inc
include msvcrt.inc

include c:\masm32\macros\macros.asm ; uses the file dated July 10, 2005

includelib kernel32.lib
includelib user32.lib
includelib masm32.lib
includelib msvcrt.lib

atoubyte     PROTO pStr:PTR BYTE, pUb :PTR BYTE
atosbyte     PROTO pStr:PTR BYTE, pSb :PTR SBYTE
ahextoubyte  PROTO pStr:PTR BYTE, pUb :PTR BYTE
atouword     PROTO pStr:PTR BYTE, pUw :PTR WORD
atosword     PROTO pStr:PTR BYTE, pSw :PTR SWORD
ahextouword  PROTO pStr:PTR BYTE, pUw :PTR WORD
atoudword    PROTO pStr:PTR BYTE, pUdw:PTR DWORD
atosdword    PROTO pStr:PTR BYTE, pSdw:PTR SDWORD
ahextoudword PROTO pStr:PTR BYTE, pUdw:PTR DWORD
atouqword    PROTO pStr:PTR BYTE, pUqw:PTR QWORD
atosqword    PROTO pStr:PTR BYTE, pSqw:PTR QWORD
ahextouqword PROTO pStr:PTR BYTE, pUqw:PTR QWORD
atoreal4     PROTO pStr:PTR BYTE, pR4 :PTR REAL4
atoreal8     PROTO pStr:PTR BYTE, pR8 :PTR REAL8
atoreal10    PROTO pStr:PTR BYTE, pR10:PTR REAL10

.DATA

szUbyMin BYTE   "0",0
szUbyMax BYTE   "255",0
szSbyMin BYTE  "-128",0
szSbyMax BYTE   "127",0
szUwdMin BYTE   "0",0
szUwdMax BYTE   "65535",0
szSwdMin BYTE  "-32768",0
szSwdMax BYTE   "32767",0
szUdwMin BYTE   "0",0
szUdwMax BYTE   "4294967295",0
szSdwMin BYTE  "-2147483648",0
szSdwMax BYTE   "2147483647",0
szUqwMin BYTE   "0",0
szUqwMax BYTE   "18446744073709551615",0
szSqwMin BYTE  "-9223372036854775808",0
szSqwMax BYTE   "9223372036854775807",0
szR4Min  BYTE  "-1.175494351E-38",0
szR4Max  BYTE   "3.402823466E+38",0
szR8Min  BYTE  "-2.2250738585072014E-308",0
szR8Max  BYTE   "1.7976931348623158E+308",0
szR10Min BYTE  "-2.2250738585072014E-308",0
szR10Max BYTE   "1.7976931348623158E+308",0
szHexBy  BYTE  "FF", 0
szHexWd  BYTE  "FFFF", 0
szHexDw  BYTE  "FFFFFFFF", 0
szHexQw  BYTE  "FFFFFFFFFFFFFFFF", 0
   
align 16
r10Max   REAL10 0.0
r10Min   REAL10 0.0
r8Max    REAL8  0.0
r8Min    REAL8  0.0
r4Max    REAL4  0.0
r4Min    REAL4  0.0
uqwMax   QWORD  0
uqwMin   QWORD  0
sqwMax   QWORD  0
sqwMin   QWORD  0
udwMax   DWORD  0
udwMin   DWORD  0
sdwMax   SDWORD 0
sdwMin   SDWORD 0
uwdMax   WORD   0
uwdMin   WORD   0
swdMax   SWORD  0
swdMin   SWORD  0
ubyMax   BYTE   0
ubyMin   BYTE   0
sbyMax   SBYTE  0
sbyMin   SBYTE  0

.CODE

start:

    ; decimal string to unsigned byte
    invoke atoubyte, ADDR szUbyMax, ADDR ubyMax
    print ubyte$(ubyMax)
    print SADD(13,10)
    invoke atoubyte, ADDR szUbyMin, ADDR ubyMin
    print ubyte$(ubyMin)
    print SADD(13,10,13,10)

    ; decimal string to signed byte
    invoke atosbyte, ADDR szSbyMax, ADDR sbyMax
    print sbyte$(sbyMax)
    print SADD(13,10)
    invoke atosbyte, ADDR szSbyMin, ADDR sbyMin
    print sbyte$(sbyMin)
    print SADD(13,10,13,10)
   
    ; hex string to unsigned byte
    invoke ahextoubyte, ADDR szHexBy, ADDR ubyMax
    print xbyte$(ubyMax)
    print SADD(13,10)
    invoke ahextoubyte, ADDR szUbyMin, ADDR ubyMin
    print xbyte$(ubyMin)
    print SADD(13,10,13,10)
   

    ; decimal string to unsigned word
    invoke atouword, ADDR szUwdMax, ADDR uwdMax
    print uword$(uwdMax)
    print SADD(13,10)   
    invoke atouword, ADDR szUwdMin, ADDR uwdMin
    print uword$(uwdMin)
    print SADD(13,10,13,10)   
   
    ; decimal string to signed word
    invoke atosword, ADDR szSwdMax, ADDR swdMax
    print sword$(swdMax)
    print SADD(13,10)   
    invoke atosword, ADDR szSwdMin, ADDR swdMin
    print sword$(swdMin)
    print SADD(13,10,13,10)
   
    ; hex string to unsigned word
    invoke ahextouword, ADDR szHexWd, ADDR uwdMax
    print xword$(uwdMax)
    print SADD(13,10)   
    invoke ahextouword, ADDR szUwdMin, ADDR uwdMin
    print xword$(uwdMin)
    print SADD(13,10,13,10)   
       
   
    ; decimal string to unsigned dword
    invoke atoudword, ADDR szUdwMax, ADDR udwMax
    print udword$(udwMax)
    print SADD(13,10)
    invoke atoudword, ADDR szUdwMin, ADDR udwMin
    print udword$(udwMin)
    print SADD(13,10,13,10)   
   
    ; decimal string to signed dword
    invoke atosdword, ADDR szSdwMax, ADDR sdwMax
    print sdword$(sdwMax)
    print SADD(13,10)
    invoke atosdword, ADDR szSdwMin, ADDR sdwMin
    print sdword$(sdwMin)
    print SADD(13,10,13,10)
   
    ; hex string to unsigned dword
    invoke ahextoudword, ADDR szHexDw, ADDR udwMax
    print xdword$(udwMax)
    print SADD(13,10)
    invoke ahextoudword, ADDR szUdwMin, ADDR udwMin
    print xdword$(udwMin)
    print SADD(13,10,13,10)
   
   
    ; decimal string to unsigned qword
    invoke atouqword, ADDR szUqwMax, ADDR uqwMax
    print uqword$(uqwMax)
    print SADD(13,10)
    invoke atouqword, ADDR szUqwMin, ADDR uqwMin
    print uqword$(uqwMin)
    print SADD(13,10,13,10)
   
    ; decimal string to signed qword
    invoke atosqword, ADDR szSqwMax, ADDR sqwMax
    print sqword$(sqwMax)
    print SADD(13,10)
    invoke atosqword, ADDR szSqwMin, ADDR sqwMin
    print sqword$(sqwMin)
    print SADD(13,10,13,10)
   
    ; hex string to unsigned qword
    invoke ahextouqword, ADDR szHexQw, ADDR uqwMax
    print xqword$(uqwMax)
    print SADD(13,10)
    invoke ahextouqword, ADDR szUqwMin, ADDR uqwMin
    print xqword$(uqwMin)
    print SADD(13,10,13,10)
   
   
    ; real4
    invoke atoreal4, ADDR szR4Max, ADDR  r4Max
    print real4$(r4Max)
    print SADD(13,10)
    invoke atoreal4, ADDR szR4Min, ADDR r4Min
    print real4$(r4Min)
    print SADD(13,10,13,10)
   
    ; real8
    invoke atoreal8, ADDR szR8Max, ADDR  r8Max
    print real8$(r8Max)
    print SADD(13,10)
    invoke atoreal8, ADDR szR8Min, ADDR r8Min
    print real8$(r8Min)
    print SADD(13,10,13,10)
   
    ; real10
    invoke atoreal10, ADDR szR10Max, ADDR  r10Max
    print real10$(r10Max)
    print SADD(13,10)
    invoke atoreal10, ADDR szR10Min, ADDR r10Min
    print real10$(r10Min)
    print SADD(13,10,13,10)
   
    invoke ExitProcess, 0

;---------------------------------------
atoubyte PROC pStr:PTR BYTE, pUb:PTR BYTE
    .data
       align 4
       ub DWORD 0   
    IFNDEF ubfmt   
    .data
        ubfmt BYTE "%hhu",0
    ENDIF 
    .code
    invoke crt_sscanf, pStr, ADDR ubfmt, ADDR ub
    mov eax, ub
    mov edx, pUb
    mov BYTE PTR [edx], al 
    ret
atoubyte ENDP 
;---------------------------------------
atosbyte PROC pStr:PTR BYTE, pSb:PTR SBYTE
    IFNDEF sb
    .data
       align 4
       sb SDWORD 0   
    ENDIF   
    IFNDEF sbfmt   
    .data
        sbfmt BYTE "%hhd",0
    ENDIF 
    .code
    invoke crt_sscanf, pStr, ADDR sbfmt, ADDR sb
    mov eax, sb
    mov edx, pSb
    mov SBYTE PTR [edx], al
    ret
atosbyte ENDP 
;---------------------------------------
ahextoubyte PROC pStr:PTR BYTE, pUb:PTR BYTE
    IFNDEF ub
    .data
       align 4
       ub DWORD 0   
    ENDIF   
    IFNDEF xbfmt   
    .data
        xbfmt BYTE "%hhX",0
    ENDIF 
    .code
    invoke crt_sscanf, pStr, ADDR xbfmt, ADDR ub
    mov eax, ub
    mov edx, pUb
    mov BYTE PTR [edx], al 
    ret
ahextoubyte ENDP 
;---------------------------------------
atouword PROC pStr:PTR BYTE, pUw:PTR WORD
    IFNDEF uw
    .data
       align 4
       uw DWORD 0   
    ENDIF   
    IFNDEF uwfmt   
    .data
        uwfmt BYTE "%hu",0
    ENDIF
    .code
    invoke crt_sscanf, pStr, ADDR uwfmt, ADDR uw
    mov eax, uw
    mov edx, pUw
    mov WORD PTR [edx], ax   
    ret
atouword ENDP   
;---------------------------------------
atosword PROC pStr:PTR BYTE, pSw:PTR SWORD
    IFNDEF sw
    .data
       align 4
       sw SDWORD 0   
    ENDIF   
    IFNDEF swfmt   
    .data
        swfmt BYTE "%hd",0
    ENDIF 
    .code
    invoke crt_sscanf, pStr, ADDR swfmt, ADDR sw
    mov eax, sw
    mov edx, pSw
    mov SWORD PTR [edx], ax     
    ret
atosword ENDP   
;---------------------------------------
ahextouword PROC pStr:PTR BYTE, pUw:PTR WORD
    IFNDEF uw
    .data
       align 4
       uw DWORD 0   
    ENDIF   
    IFNDEF xwfmt   
    .data
        xwfmt BYTE "%hX",0
    ENDIF
    .code
    invoke crt_sscanf, pStr, ADDR xwfmt, ADDR uw
    mov eax, uw
    mov edx, pUw
    mov WORD PTR [edx], ax   
    ret
ahextouword ENDP   
;---------------------------------------
atoudword PROC pStr:PTR BYTE, pUdw:PTR DWORD
    IFNDEF udw
    .data
        align 4
        udw DWORD 0   
    ENDIF   
    IFNDEF udwfmt   
    .data
        udwfmt BYTE "%u",0
    ENDIF
    .code
    invoke crt_sscanf, pStr, ADDR udwfmt, ADDR udw
    mov eax, udw
    mov edx, pUdw
    mov DWORD PTR [edx], eax
    ret
atoudword ENDP   
;---------------------------------------
atosdword PROC pStr:PTR BYTE, pSdw:PTR SDWORD
    IFNDEF sdw
    .data
       align 4
       sdw SDWORD 0   
    ENDIF   
    IFNDEF sdwfmt   
    .data
        sdwfmt BYTE "%d",0
    ENDIF   
    .code
    invoke crt_sscanf, pStr, ADDR sdwfmt, ADDR sdw
    mov eax, sdw
    mov edx, pSdw
    mov SDWORD PTR [edx], eax   
    ret
atosdword ENDP   
;---------------------------------------
ahextoudword PROC pStr:PTR BYTE, pUdw:PTR DWORD
    IFNDEF udw
    .data
        align 4
        udw DWORD 0   
    ENDIF   
    IFNDEF xdwfmt   
    .data
        xdwfmt BYTE "%X",0
    ENDIF
    .code
    invoke crt_sscanf, pStr, ADDR xdwfmt, ADDR udw
    mov eax, udw
    mov edx, pUdw
    mov DWORD PTR [edx], eax
    ret
ahextoudword ENDP   
;---------------------------------------
atouqword PROC pStr:PTR BYTE, pUqw:PTR QWORD
    IFNDEF uqw
    .data
       align 8
       uqw QWORD 0   
    ENDIF   
    IFNDEF uqwfmt   
    .data
        uqwfmt BYTE "%I64u",0
    ENDIF   
    .code
    invoke crt_sscanf, pStr, ADDR uqwfmt, ADDR uqw
    mov edx, pUqw
    mov eax, DWORD PTR [uqw+4]
    mov DWORD PTR [edx+4], eax
    mov eax, DWORD PTR [uqw+0]
    mov DWORD PTR [edx+0], eax
    ret
atouqword ENDP   
;---------------------------------------
atosqword PROC pStr:PTR BYTE, pSqw:PTR QWORD
    IFNDEF sqw
    .data
       align 8
       sqw QWORD 0   
    ENDIF   
    IFNDEF sqwfmt   
    .data
        sqwfmt BYTE "%I64d",0
    ENDIF   
    .code
    invoke crt_sscanf, pStr, ADDR sqwfmt, ADDR sqw
    mov edx, pSqw
    mov eax, DWORD PTR [sqw+4]
    mov DWORD PTR [edx+4], eax
    mov eax, DWORD PTR [sqw+0]
    mov DWORD PTR [edx+0], eax
    ret
atosqword ENDP   
;-------------------------------------------
ahextouqword PROC pStr:PTR BYTE, pUqw:PTR QWORD
    IFNDEF uqw
    .data
       align 8
       uqw QWORD 0   
    ENDIF   
    IFNDEF xqwfmt   
    .data
        xqwfmt BYTE "%I64X",0
    ENDIF   
    .code
    invoke crt_sscanf, pStr, ADDR xqwfmt, ADDR uqw
    mov edx, pUqw
    mov eax, DWORD PTR [uqw+4]
    mov DWORD PTR [edx+4], eax
    mov eax, DWORD PTR [uqw+0]
    mov DWORD PTR [edx+0], eax
    ret
ahextouqword ENDP   
;---------------------------------------
atoreal4 PROC pStr:PTR BYTE, pR4:PTR REAL4
    IFNDEF r4fmt   
    .data
        r4fmt BYTE "%f",0
    ENDIF   
    .code
    invoke crt_sscanf, pStr, ADDR r4fmt, pR4
    ret
atoreal4 ENDP   
;-------------------------------------------
atoreal8 PROC pStr:PTR BYTE, pR8:PTR REAL8
    IFNDEF r8fmt   
    .data
        r8fmt BYTE "%lf",0
    ENDIF
    .code
    invoke crt_sscanf, pStr, ADDR r8fmt, pR8
    ret
atoreal8 ENDP   
;--------------------------------------------
atoreal10 PROC pStr:PTR BYTE, pR10:PTR REAL10
    IFNDEF r8
    .data
       align 8
       r8 REAL8 0.0
    ENDIF   
    IFNDEF r8fmt   
    .data
        r8fmt BYTE "%lf",0
    ENDIF   
    .code
    invoke crt_sscanf, pStr, ADDR r8fmt, ADDR r8
    mov eax, pR10
    finit
    fld r8
    fstp REAL10 PTR [eax]
    ret
atoreal10 ENDP
;--------------------------------------------

end start







[attachment deleted by admin]
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 11, 2005, 04:32:35 AM
Updated above, changed data in procedures to LOCAL.

Updated again, eliminated unnecessary code.

I'm done for tonight.  :bg

Updated again, added hex string support.

 
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 11, 2005, 05:44:47 AM
Thanks Greg,

Another masterpiece.  :U
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 11, 2005, 03:14:42 PM
This is an unrelated question. Whenever I have tried to use the internal notation within a quoted string of \t or \n I only ever get those characters as literals in the displayed string and not the TAB or CRLF. Am I missing something in how I format the strings.


fn crt_printf,"%s","This \t is a test\n"


I have checked the macros 1st pass and the normal string content is written to the .DATA section so it is passed as a normal zero terminated string.
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 11, 2005, 06:02:48 PM
Hutch,

I know, I ran into the same thing. I thought that would work too, but it doesn't. I think the C compiler replaces the "\t" or "\n" in the string with the actual character code like 9 or 10 at compile-time, so in MASM we have to manually do what the C compiler automatically does.

Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 11, 2005, 07:28:37 PM
More input/output macros that use C run-time library functions. I know MASM32 already has macros that do these things. I'm just exploring what can be done with the CRT functions in MASM32.


.586
.MODEL FLAT, stdcall
option casemap:none

include windows.inc

include kernel32.inc
include user32.inc
include masm32.inc
include msvcrt.inc

include c:\masm32\macros\macros.asm

includelib kernel32.lib
includelib user32.lib
includelib masm32.lib
includelib msvcrt.lib

;-----------------------------------------------------
linein MACRO   
    ; Usage: mov eax, linein()
    LOCAL buffer
    .data?
        buffer BYTE 96 dup(?)
    IFNDEF strFmt   
    .data
        strFmt BYTE "%s", 0
    ENDIF
    IFNDEF Cr
    .data
        dwNewLine DWORD 10
    ENDIF   
    .code   
    invoke crt_fgets, ADDR buffer, SIZEOF buffer, crt__iob
    push eax
    invoke crt_strchr, ADDR buffer, dwNewLine
    .if eax
        mov BYTE PTR [eax], 0   ; remove the newline from buffer
    .endif   
    pop eax
    EXITM <eax>
ENDM   
;-----------------------------------------------------
lineout MACRO pStr
    ; Usage: lineout chr$("Hello")
    ; Replaces the trailing nul character
    ; with a linefeed.
    IFNB <pStr>
        invoke crt_puts, pStr
    ELSE
        invoke crt_puts, chr$(0)
    ENDIF
ENDM
;-----------------------------------------------------
printstr MACRO pStr:req
    ;Usage: printstr chr$("Hello")
    invoke crt_printf, pStr
ENDM   
;-----------------------------------------------------
WaitKey MACRO
    lineout
    printstr chr$("Press any key to exit...")
    invoke wait_key
    lineout
ENDM
;-----------------------------------------------------

.DATA

    lpInput DWORD 0

.CODE

start:
   
    lineout chr$("Input/Output Test")
    lineout
    printstr chr$("Enter some text: ")
    mov lpInput, linein()
    printstr chr$("You entered:     ")
    lineout lpInput
       
    WaitKey
    invoke ExitProcess, 0

end start

Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 11, 2005, 10:02:23 PM
An example of using floating-point CRT functions.


.586
.MODEL FLAT, stdcall
option casemap:none

include windows.inc

include kernel32.inc
include user32.inc
include masm32.inc
include msvcrt.inc

include c:\masm32\macros\macros.asm

includelib kernel32.lib
includelib user32.lib
includelib masm32.lib
includelib msvcrt.lib

Sine       PROTO degrees:PTR REAL8,     sin:PTR REAL8
Cosine     PROTO degrees:PTR REAL8,     cos:PTR REAL8
Tangent    PROTO degrees:PTR REAL8,     tan:PTR REAL8
Arcsine    PROTO sin    :PTR REAL8, degrees:PTR REAL8
Arccosine  PROTO cos    :PTR REAL8, degrees:PTR REAL8
Arctangent PROTO tan    :PTR REAL8, degrees:PTR REAL8
inputR4    PROTO pR4    :PTR REAL4
inputR8    PROTO pR8    :PTR REAL8
inputR10   PROTO pR10   :PTR REAL10

;---------------------------------------
; macros
;---------------------------------------
printf MACRO pszFmt, args:VARARG
    IFB <args>
        IFB <pszFmt>
            invoke crt_printf, chr$(13,10)
        ELSE   
            invoke crt_printf, pszFmt
        ENDIF
    ELSE
        invoke crt_printf, pszFmt, args
    ENDIF   
ENDM   
;---------------------------------------
WaitKey MACRO
    printf chr$(13,10,"Press any key to continue...")
    call wait_key
    printf
ENDM
;---------------------------------------

.DATA

    dblDegrees     REAL8   0.0
    dblSine        REAL8   0.0
    dblCosine      REAL8   0.0
    dblTangent     REAL8   0.0
           
.CODE

start:

    printf chr$("Enter angle in degrees: ")
    invoke inputR8, ADDR dblDegrees
       
    printf
    printf chr$("Angle                 = %9.6lf degrees",13, 10), dblDegrees
                   
    invoke Sine, ADDR dblDegrees, ADDR dblSine
    invoke Cosine, ADDR dblDegrees, ADDR dblCosine
    invoke Tangent, ADDR dblDegrees, ADDR dblTangent
       
    printf
    printf chr$("Sine(%.0lf)              = %8.6lf", 13, 10), dblDegrees, dblSine
    printf chr$("Cosine(%.0lf)            = %8.6lf", 13, 10), dblDegrees, dblCosine
    printf chr$("Tangent(%.0lf)           = %8.6lf", 13, 10), dblDegrees, dblTangent
    printf
           
    invoke Arcsine, ADDR dblSine, ADDR dblDegrees
    printf chr$("Arcsine(%8.6lf)     = %9.6lf degrees", 13, 10), dblSine, dblDegrees
 
    invoke Arccosine, ADDR dblCosine, ADDR dblDegrees
    printf chr$("Arccosine(%8.6lf)   = %9.6lf degrees", 13, 10), dblCosine, dblDegrees
   
    invoke Arctangent, ADDR dblTangent, ADDR dblDegrees
    printf chr$("Arctangent(%8.6lf)  = %9.6lf degrees", 13, 10), dblTangent, dblDegrees
               
    WaitKey
       
    invoke ExitProcess, 0

;======================================================
; procedures
;======================================================
Sine PROC degrees:PTR REAL8, sin:PTR REAL8
    LOCAL radians:REAL8
    IFNDEF DtoR
        .CONST
            DtoR    REAL10 0.017453292519943295769  ;(Pi / 180.0)
    ENDIF   
    .CODE
        mov     eax, degrees
        finit
        fld     REAL8 PTR [eax]
        fld     DtoR
        fmul
        fstp    radians
        fwait
        invoke  crt_sin, radians    ;result in ST(0)
        mov     eax, sin
        fstp    REAL8 PTR [eax]
        fwait
        ret
Sine ENDP
;======================================================
Cosine PROC degrees:PTR REAL8, cos:PTR REAL8
    LOCAL radians:REAL8
    IFNDEF DtoR
        .CONST
            DtoR    REAL10 0.017453292519943295769  ;(Pi / 180.0)
    ENDIF   
    .CODE
        mov     eax, degrees
        finit
        fld     REAL8 PTR [eax]
        fld     DtoR
        fmul
        fstp    radians
        fwait
        invoke  crt_cos, radians    ;result in ST(0)
        mov     eax, cos
        fstp    REAL8 PTR [eax]
        fwait
        ret
Cosine ENDP
;======================================================
Tangent PROC degrees:PTR REAL8, tan:PTR REAL8
    LOCAL radians:REAL8
    IFNDEF DtoR
        .CONST
            DtoR    REAL10 0.017453292519943295769  ;(Pi / 180.0)
    ENDIF   
    .CODE
        mov     eax, degrees
        finit
        fld     REAL8 PTR [eax]
        fld     DtoR
        fmul
        fstp    radians
        fwait
        invoke  crt_tan, radians    ;result in ST(0)
        mov     eax, tan
        fstp    REAL8 PTR [eax]
        fwait
        ret
Tangent ENDP
;======================================================
Arcsine PROC sin:PTR REAL8, degrees:PTR REAL8
    IFNDEF RtoD
        .CONST
            RtoD    REAL10 57.295779513082320876798  ;(180.0 / Pi)
    ENDIF       
    .CODE
        mov     eax, sin
        invoke  crt_asin, REAL8 PTR [eax]    ;result in ST(0)
        mov     eax, degrees
        fld     RtoD
        fmul
        fstp    REAL8 PTR [eax]
        fwait
        ret
Arcsine ENDP
;======================================================
Arccosine PROC cos:PTR REAL8, degrees:PTR REAL8
    IFNDEF RtoD
        .CONST
            RtoD    REAL10 57.295779513082320876798  ;(180.0 / Pi)
    ENDIF   
    .CODE
        mov     eax, cos
        invoke  crt_acos, REAL8 PTR [eax]    ;result in ST(0)
        mov     eax, degrees
        fld     RtoD
        fmul
        fstp    REAL8 PTR [eax]
        fwait
        ret
Arccosine ENDP
;======================================================
Arctangent PROC tan:PTR REAL8, degrees:PTR REAL8
    IFNDEF RtoD
        .CONST
            RtoD    REAL10 57.295779513082320876798  ;(180.0 / Pi)
    ENDIF   
    .CODE
        mov     eax, tan
        invoke  crt_atan, REAL8 PTR [eax]    ;result in ST(0)
        mov     eax, degrees
        fld     RtoD
        fmul
        fstp    REAL8 PTR [eax]
        fwait
        ret
Arctangent ENDP
;======================================================
inputR4 PROC pR4:PTR REAL4
    invoke crt_scanf, chr$("%f"), pR4
    ret
inputR4 ENDP
;======================================================
inputR8 PROC pR8:PTR REAL8
    invoke crt_scanf, chr$("%lf"), pR8
    ret
inputR8 ENDP
;======================================================
inputR10 PROC pR10:PTR REAL10
    LOCAL r8:REAL8
    invoke crt_scanf, chr$("%lf"), ADDR r8
    mov eax, pR10
    finit
    fld r8
    fstp REAL10 PTR [eax]
    fwait
    ret
inputR10 ENDP
;======================================================
end start

   
Title: Re: Suggestion with MSVCRT code.
Post by: Vortex on July 12, 2005, 05:27:13 AM
Nice work.

Technically, what's the difference between msvcrt.dll and crtdll.dll ?
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 12, 2005, 06:02:55 PM
Vortex,

Good question, it's not real clear in my mind either. Here are some links I found:

    How To Use the C Run-Time (http://support.microsoft.com/default.aspx?scid=kb;en-us;94248)

    How to link with the correct C Run-Time (CRT) library (http://support.microsoft.com/default.aspx?scid=kb;en-us;140584)

    C Run-Time Libraries (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_CRT_C_Run.2d.Time_Libraries.asp)


I have also been trying out using pocrt, as it supports some handy C99 stuff that msvcrt does not. With it we're back to the naming conflicts problem with the MASM32 library. How Hutch modified the .inc and .lib for msvcrt is beyond me at this point.   

Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 13, 2005, 12:15:31 AM
Hutch (and anyone else that is interested),

Regarding the sprintf conversion macros:

Something I noticed, if a REAL8 is passed to the real4$ macro, the buffer could possibly overflow since the REAL4 gets converted to a REAL8 for the function call. Why am I dong this? Because the C compiler generates code to convert the REAL4 to a REAL8 for the call to sprintf. If you pass sprintf a REAL4 it doesn't work correctly.

  1) increase the buffer to 320 to allow for DBL_MAX.
  2) Somehow only allow a REAL4 to be passed to the macro.

I also noticed that the buffers in all the macros should be initialized to 0 so that if sprintf fails the buffer string is terminated.

What do you think? I'd be glad to make these changes.

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 13, 2005, 01:31:50 AM
Greg,

There is a toy in the latest service pack that solves this problem. MAKECIMP will work on any list of procedure names to produce an include file and a LIB file. It automatically prepends "crt_" to the function names in the include but all you need to do is do a global replace of "crt_" with another prefix and you solve the name duplication problem.

Initialising the buffer is a good idea, all you need to do is write a single zero as the first byte in the buffer, it does not ned to be zero filled.
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 13, 2005, 03:24:26 AM
Hutch,

Thanks for pointing me to MAKECIMP, I had forgotten all about it. I was able to make a pocrt.inc and pocrt.lib with it and they work. The only drawback is pocrt.dll isn't already on every Windows PC like msvcrt.dll is.

Would you recommend changing the  .data?  section to  .data  or add a  mov buffer[0],0  to the code?

In the real4$ macro, if I use the VarR8FromR4 API function, I get an assembly error if I pass it anything other than a REAL4, thanks to invoke.

Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 13, 2005, 04:18:47 AM
Well it's getting late here, so I'll post what I have done with the sprintf macros.


.586
.MODEL FLAT, stdcall
option casemap:none

include c:\masm32\include\windows.inc

include c:\masm32\include\kernel32.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\masm32.inc
include c:\masm32\include\msvcrt.inc
include c:\masm32\include\oleaut32.inc

include c:\masm32\macros\macros.asm

includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\masm32.lib
includelib c:\masm32\lib\msvcrt.lib
includelib c:\masm32\lib\oleaut32.lib

;; ----------------------------------------------
ubyte$ MACRO ubytevalue:req
    ; unsigned byte
    LOCAL buffer
    .data?
        buffer BYTE 4 dup(?)
    IFNDEF ubfmt   
    .data   
        ubfmt  BYTE "%hhu", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    al, ubytevalue
        movzx  eax, al
        invoke crt_sprintf, ADDR buffer, ADDR ubfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sbyte$ MACRO sbytevalue:req
    ; signed byte
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF sbfmt     
    .data   
        sbfmt  BYTE "%hhd", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    al, sbytevalue
        movsx  eax, al
        invoke crt_sprintf, ADDR buffer, ADDR sbfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xbyte$ MACRO xbytevalue:req
    ; unsigned hex byte
    LOCAL buffer
    .data?
        buffer BYTE 4 dup(?)
    IFNDEF xbfmt   
    .data   
        xbfmt  BYTE "%hhX", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    al, xbytevalue
        movzx  eax, al
        invoke crt_sprintf, ADDR buffer, ADDR xbfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
uword$ MACRO uwordvalue:req
    ; unsigned word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF uwfmt   
    .data   
        uwfmt  BYTE "%hu", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        mov   ax, uwordvalue
        movzx eax, ax
        invoke crt_sprintf, ADDR buffer, ADDR uwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sword$ MACRO swordvalue:req
    ; signed word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF swfmt   
    .data   
        swfmt  BYTE "%hd", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        mov   ax, swordvalue
        movsx eax, ax
        invoke crt_sprintf, ADDR buffer, ADDR swfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xword$ MACRO xwordvalue:req
    ; unsigned hex word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF xwfmt   
    .data   
        xwfmt  BYTE "%hX", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        mov   ax, xwordvalue
        movzx eax, ax
        invoke crt_sprintf, ADDR buffer, ADDR xwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
udword$ MACRO udwordvalue:req
    ; unsigned dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF udwfmt   
    .data   
        udwfmt BYTE "%lu", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    eax, udwordvalue
        invoke crt_sprintf, ADDR buffer, ADDR udwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sdword$ MACRO sdwordvalue:req
    ; signed dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF sdwfmt   
    .data   
        sdwfmt BYTE "%ld", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    eax, sdwordvalue
        invoke crt_sprintf, ADDR buffer, ADDR sdwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xdword$ MACRO xdwordvalue:req
    ; unsigned hex dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF xdwfmt   
    .data   
        xdwfmt BYTE "%lX", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    eax, xdwordvalue
        invoke crt_sprintf, ADDR buffer, ADDR xdwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
uqword$ MACRO uqwordvalue:req
    ; unsigned qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF uqwfmt   
    .data   
        uqwfmt BYTE "%I64u", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR uqwfmt, uqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sqword$ MACRO sqwordvalue:req
    ; signed qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF sqwfmt   
    .data   
        sqwfmt BYTE "%I64d", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR sqwfmt, sqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xqword$ MACRO xqwordvalue:req
    ; unsigned hex qword
    LOCAL buffer
    .data?
        buffer BYTE 20 dup(?)
    IFNDEF xqwfmt   
    .data   
        xqwfmt BYTE "%I64X", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR xqwfmt, xqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real4$ MACRO r4value:req
    LOCAL buffer, r8value
    .data?
        r8value REAL8 ?
        buffer  BYTE  48 dup(?)
    IFNDEF r8fmt   
    .data
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke VarR8FromR4, r4value, ADDR r8value
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real8$ MACRO r8value:req
    LOCAL buffer
    .data?
        buffer BYTE 320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt  BYTE "%lf", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real10$ MACRO r10value:req
    LOCAL buffer, r8value
    .data?
        r8value REAL8 ?
        buffer  BYTE  320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        finit
        fld    REAL10 PTR r10value
        fstp   r8value
        fwait
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
WaitKey MACRO
    LOCAL szCrLf, szPAK
    .data
        szCrLf BYTE 13, 10, 0
        szPAK  BYTE 13, 10, "Press any key to continue...", 0
    .code   
        invoke crt_printf, ADDR szPAK
        call crt__getch
        .if (eax == 0) || (eax == 0E0h)
            call crt__getch
        .endif
        invoke crt_printf, ADDR szCrLf
ENDM
;; ----------------------------------------------

.DATA
       
    ubyMax BYTE   255                        ; UCHAR_MAX
    ubyMin BYTE     0                        ; UCHAR_MIN
   
    sbyMax SBYTE  127                        ; CHAR_MAX
    sbyMin SBYTE -128                        ; CHAR_MIN
   
    uwdMax WORD   65535                      ; USHRT_MAX
    uwdMin WORD       0                      ; USHRT_MIN
   
    swdMax SWORD  32767                      ; SHRT_MAX
    swdMin SWORD -32768                      ; SHRT_MIN
   
    udwMax DWORD   4294967295                ; ULONG MAX
    udwMin DWORD            0                ; ULONG_MIN
   
    sdwMax SDWORD  2147483647                ; LONG_MAX
    sdwMin SDWORD -2147483648                ; LONG_MIN
   
    uqwMax QWORD 18446744073709551615        ; _UI64_MAX
    uqwMin QWORD                    0        ; _UI64_MIN
   
    sqwMax QWORD  9223372036854775807        ; _I64_MAX
    sqwMin QWORD -9223372036854775808        ; _I64_MIN
   
    r4Max  REAL4   3.402823466E+38           ; FLT_MAX
    r4Min  REAL4  -1.175494351E-38           ; FLT_MIN
   
    r8Max  REAL8   1.7976931348623158E+308   ; DBL_MAX
    r8Min  REAL8  -2.2250738585072014E-308   ; DBL_MIN
   
    r10Max REAL10  1.7976931348623158E+308   ; LDBL_MAX ( = DBL_MAX)
    r10Min REAL10 -2.2250738585072014E-308   ; LDBL_MIN ( = DBL_MIN)
       
.CODE

start:
       
    invoke crt_puts, ubyte$(ubyMax)
    invoke crt_puts, ubyte$(ubyMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sbyte$(sbyMax)
    invoke crt_puts, sbyte$(sbyMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xbyte$(ubyMax)
    invoke crt_puts, xbyte$(ubyMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, uword$(uwdMax)
    invoke crt_puts, uword$(uwdMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sword$(swdMax)
    invoke crt_puts, sword$(swdMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xword$(uwdMax)
    invoke crt_puts, xword$(uwdMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, udword$(udwMax)
    invoke crt_puts, udword$(udwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sdword$(sdwMax)
    invoke crt_puts, sdword$(sdwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xdword$(udwMax)
    invoke crt_puts, xdword$(udwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, uqword$(uqwMax)
    invoke crt_puts, uqword$(uqwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, sqword$(sqwMax)
    invoke crt_puts, sqword$(sqwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, xqword$(uqwMax)
    invoke crt_puts, xqword$(uqwMin)
    invoke crt_puts, SADD(0)
    invoke crt_puts, real4$(r4Max)
    invoke crt_puts, real4$(r4Min)
    invoke crt_puts, SADD(0)
    invoke crt_puts, real8$(r8Max)
    invoke crt_puts, real8$(r8Min)
    invoke crt_puts, SADD(0)
    invoke crt_puts, real10$(r10Max)
    invoke crt_puts, real10$(r10Min)
           
    WaitKey
         
    invoke ExitProcess, 0

end start


Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 13, 2005, 04:39:27 AM
On second thought VarR8FromR4 is not very good because it requires an oddball .inc and .lib (oleaut32).  ::)

I'm going to sleep on it.

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 13, 2005, 06:10:34 AM
Greg,

I would be inclined to set the buffer to zero dynamically rather than set the section to initialised data as it is more size efficient.
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 13, 2005, 06:11:51 PM
Hutch,



Regarding initializing the buffer:

  Good, that's what I thought too, done.



Regarding the possible buffer overflow if a REAL8 is passed to the real4$ macro:

1) Increase the buffer size to 320.

2) Use VarR8FromR4 for the conversion. If called with invoke it causes an assembly-time error if the wrong data type is passed. It requires including oleaut32.inc/.lib.

real4$ MACRO r4value:req
    LOCAL buffer, r8value
    .data?
        r8value REAL8 ?
        buffer  BYTE  48 dup(?)
    IFNDEF r8fmt   
    .data
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke VarR8FromR4, r4value, ADDR r8value
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM


3) Force the FPU to load a REAL4. It solves the possible buffer overflow but does not cause an assembly-time error.

real4$ MACRO r4value:req
    LOCAL buffer, r8value
    .data?
        r8value REAL8 ?
        buffer  BYTE  48 dup(?)
    IFNDEF r8fmt   
    .data
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        finit
        fld    REAL4 PTR r4value
        fstp   r8value
        fwait
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM


If someone has a better idea please speak up.

I prefer #2, but it's up to you Hutch.

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 14, 2005, 12:07:10 AM
Greg,

This may be a simple solution and it means the user must get the data type correct.


    tst4 MACRO arg
      IF op_type(arg) EQ 4                  ;; if integer register
        echo -------------------------------
        echo REAL4 Memory operand expected.
        echo Integer register not allowed in
        echo this context.
        echo -------------------------------
        .err
      ENDIF
      IF SIZEOF arg NE 4                    ;; if not 4 bytes
        echo -------------------------------
        echo data size error, requires REAL4
        echo -------------------------------
        .err
      ENDIF
    ENDM

Tested with this code.

    tst4 FP4(1234.5678)

Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 14, 2005, 12:50:07 AM
Hutch,

I like it. Your experience with MASM is showing, and my lack of experience with MASM is showing. :bg I had never used .ERR before. That method could be used in the other macros, but I'm not sure they need it.

Here are the sprintf conversion macros with my concerns addressed:

;; ----------------------------------------------
tst4 MACRO arg
    IF op_type(arg) EQ 4                  ;; if integer register
        echo -------------------------------
        echo REAL4 Memory operand expected.
        echo Integer register not allowed in
        echo this context.
        echo -------------------------------
       .err
    ENDIF
    IF SIZEOF arg NE 4                    ;; if not 4 bytes
        echo -------------------------------
        echo data size error, requires REAL4
        echo -------------------------------
       .err
  ENDIF
ENDM
;; ----------------------------------------------
ubyte$ MACRO ubytevalue:req
    ; unsigned byte
    LOCAL buffer
    .data?
        buffer BYTE 4 dup(?)
    IFNDEF ubfmt   
    .data   
        ubfmt  BYTE "%hhu", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    al, ubytevalue
        movzx  eax, al
        invoke crt_sprintf, ADDR buffer, ADDR ubfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sbyte$ MACRO sbytevalue:req
    ; signed byte
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF sbfmt     
    .data   
        sbfmt  BYTE "%hhd", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    al, sbytevalue
        movsx  eax, al
        invoke crt_sprintf, ADDR buffer, ADDR sbfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xbyte$ MACRO xbytevalue:req
    ; unsigned hex byte
    LOCAL buffer
    .data?
        buffer BYTE 4 dup(?)
    IFNDEF xbfmt   
    .data   
        xbfmt  BYTE "%hhX", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    al, xbytevalue
        movzx  eax, al
        invoke crt_sprintf, ADDR buffer, ADDR xbfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
uword$ MACRO uwordvalue:req
    ; unsigned word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF uwfmt   
    .data   
        uwfmt  BYTE "%hu", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        mov   ax, uwordvalue
        movzx eax, ax
        invoke crt_sprintf, ADDR buffer, ADDR uwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sword$ MACRO swordvalue:req
    ; signed word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF swfmt   
    .data   
        swfmt  BYTE "%hd", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        mov   ax, swordvalue
        movsx eax, ax
        invoke crt_sprintf, ADDR buffer, ADDR swfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xword$ MACRO xwordvalue:req
    ; unsigned hex word
    LOCAL buffer
    .data?
        buffer BYTE 8 dup(?)
    IFNDEF xwfmt   
    .data   
        xwfmt  BYTE "%hX", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        mov   ax, xwordvalue
        movzx eax, ax
        invoke crt_sprintf, ADDR buffer, ADDR xwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
udword$ MACRO udwordvalue:req
    ; unsigned dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF udwfmt   
    .data   
        udwfmt BYTE "%lu", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    eax, udwordvalue
        invoke crt_sprintf, ADDR buffer, ADDR udwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sdword$ MACRO sdwordvalue:req
    ; signed dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF sdwfmt   
    .data   
        sdwfmt BYTE "%ld", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    eax, sdwordvalue
        invoke crt_sprintf, ADDR buffer, ADDR sdwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xdword$ MACRO xdwordvalue:req
    ; unsigned hex dword
    LOCAL buffer
    .data?
        buffer BYTE 12 dup(?)
    IFNDEF xdwfmt   
    .data   
        xdwfmt BYTE "%lX", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        mov    eax, xdwordvalue
        invoke crt_sprintf, ADDR buffer, ADDR xdwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
uqword$ MACRO uqwordvalue:req
    ; unsigned qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF uqwfmt   
    .data   
        uqwfmt BYTE "%I64u", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR uqwfmt, uqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sqword$ MACRO sqwordvalue:req
    ; signed qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF sqwfmt   
    .data   
        sqwfmt BYTE "%I64d", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR sqwfmt, sqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xqword$ MACRO xqwordvalue:req
    ; unsigned hex qword
    LOCAL buffer
    .data?
        buffer BYTE 20 dup(?)
    IFNDEF xqwfmt   
    .data   
        xqwfmt BYTE "%I64X", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR xqwfmt, xqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real4$ MACRO r4value:req
    LOCAL buffer, r8value
    .data?
        r8value REAL8 ?
        buffer  BYTE  48 dup(?)
    IFNDEF r8fmt   
    .data
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        tst4   r4value
        finit
        fld    r4value
        fstp   r8value
        fwait
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real8$ MACRO r8value:req
    LOCAL buffer
    .data?
        buffer BYTE 320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt  BYTE "%lf", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real10$ MACRO r10value:req
    LOCAL buffer, r8value
    .data?
        r8value REAL8 ?
        buffer  BYTE  320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        finit
        fld    r10value
        fstp   r8value
        fwait
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------


Title: Re: Suggestion with MSVCRT code.
Post by: Howard on July 14, 2005, 02:35:39 AM
Hi

QuoteThis is an unrelated question. Whenever I have tried to use the internal notation within a quoted string of \t or \n I only ever get those characters as literals in the displayed string and not the TAB or CRLF. Am I missing something in how I format the strings.


Not having followed things too closely this may be a foolish comment, but normally to get an escape sequence recognized in a string in C I used to have to write it as "\\t" instead of "\t". Have you tried that?

Howard
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 14, 2005, 03:17:15 AM
Howard,

Sad to say I tried that one but it just displays the \\n in the text. I think Greg is right that the compiler expands the text before its sent to the procedure.
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 14, 2005, 03:14:37 PM
Greg,

Here is some macro code that may be useful as well.


    % echo num2str(TYPE(reg))

      IF TYPE(reg) NE 4
        echo ------------------------
        echo 32 bit register required
        echo ------------------------
        .err
      ENDIF


I can get TYPE to recognise 2, 4 and 10 byte registers. It fails on 1 byte regs and does not appear to work correctly on mm or xmm registers.
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 14, 2005, 09:43:47 PM
Hutch,

Just using TYPE would be simpler. It seems to be the same as using just SIZE. What's eluding me is how to determine if a 32-bit variable is a REAL4 or not. I have been reading the MASM manuals and I don't see a way to do it. MASM doesn't seem to differentiate between DWORD and REAL4 or QWORD and REAL8. They seem to be just aliases. I like to use them though for clarity. You could use FXAM but that would only tell you whether a number is a valid floating-point or not, which the bit pattern of many integers would be considered as.

One thing I don't like about the current macro is you can't pass a REAL4 in a 32-bit register, as FLD won't load a CPU register.

What do you think of this, it does the size checking and allows passing a REAL4 in a 32-bit register too.

;; ----------------------------------------------
real4$ MACRO r4value:req
    LOCAL buffer, r8value, r4tmp
    .data?
        r4tmp   REAL4 ?
        r8value REAL8 ?
        buffer  BYTE  48 dup(?)
    IFNDEF r8fmt   
    .data
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        push   r4value
        pop    r4tmp
        finit
        fld    r4tmp
        fstp   r8value
        fwait
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------


Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 15, 2005, 02:27:19 AM
I think I have it now. The macros accept both memory and register variables.

sprintf macros


.586
.MODEL FLAT, stdcall
option casemap:none

include c:\masm32\include\windows.inc

include c:\masm32\include\kernel32.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\masm32.inc
include c:\masm32\include\msvcrt.inc

include c:\masm32\macros\macros.asm

includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\masm32.lib
includelib c:\masm32\lib\msvcrt.lib

;; ----------------------------------------------
isregister MACRO tst
    IF op_type(tst) EQ 4
        EXITM <1>
    ELSE
        EXITM <0>
    ENDIF
ENDM   
;; ----------------------------------------------
ubyte$ MACRO ubytevalue:req
    ; unsigned byte
    LOCAL buffer, ubtmp
    .data?
        ubtmp  BYTE ?
        buffer BYTE 4 dup(?)
    IFNDEF ubfmt   
    .data   
        ubfmt  BYTE "%hhu", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        IF isregister(ubytevalue)
            mov   ubtmp, ubytevalue
            movzx eax, ubtmp
        ELSE
            mov   al, ubytevalue
            movzx eax, al
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR ubfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sbyte$ MACRO sbytevalue:req
    ; signed byte
    LOCAL buffer, sbtmp
    .data?
        sbtmp  SBYTE ?
        buffer BYTE  8 dup(?)
    IFNDEF sbfmt     
    .data   
        sbfmt  BYTE "%hhd", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        IF isregister(sbytevalue)
            mov   sbtmp, sbytevalue
            movsx eax, sbtmp
        ELSE     
            mov   al, sbytevalue
            movsx eax, al
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR sbfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xbyte$ MACRO xbytevalue:req
    ; unsigned hex byte
    LOCAL buffer, xbtmp
    .data?
        xbtmp  BYTE ?
        buffer BYTE 4 dup(?)
    IFNDEF xbfmt   
    .data   
        xbfmt  BYTE "%hhX", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        IF isregister(xbytevalue)
            mov   xbtmp, xbytevalue
            movzx eax, xbtmp
        ELSE
            mov   al, xbytevalue
            movzx eax, al
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR xbfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
uword$ MACRO uwordvalue:req
    ; unsigned word
    LOCAL buffer, uwtmp
    .data?
        uwtmp  WORD ?
        buffer BYTE 8 dup(?)
    IFNDEF uwfmt   
    .data   
        uwfmt  BYTE "%hu", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        IF isregister(uwordvalue)
            mov   uwtmp, uwordvalue
            movzx eax, uwtmp
        ELSE       
            mov   ax, uwordvalue
            movzx eax, ax
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR uwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sword$ MACRO swordvalue:req
    ; signed word
    LOCAL buffer, swtmp
    .data?
        swtmp  SWORD ?
        buffer BYTE  8 dup(?)
    IFNDEF swfmt   
    .data   
        swfmt  BYTE "%hd", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        IF isregister(swordvalue)
            mov   swtmp, swordvalue
            movsx eax, swtmp
        ELSE   
            mov   ax, swordvalue
            movsx eax, ax
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR swfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xword$ MACRO xwordvalue:req
    ; unsigned hex word
    LOCAL buffer, xwtmp
    .data?
        xwtmp  WORD ?
        buffer BYTE 8 dup(?)
    IFNDEF xwfmt   
    .data   
        xwfmt  BYTE "%hX", 0
    ENDIF   
    .code
        mov   buffer[0], 0
        IF isregister(xwordvalue)
            mov   xwtmp, xwordvalue
            movzx eax, xwtmp
        ELSE               
            mov   ax, xwordvalue
            movzx eax, ax
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR xwfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
udword$ MACRO udwordvalue:req
    ; unsigned dword
    LOCAL buffer, udtmp
    .data?
        udtmp  DWORD ?
        buffer BYTE  12 dup(?)
    IFNDEF udfmt   
    .data   
        udfmt  BYTE "%lu", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        IF isregister(udwordvalue)
            mov udtmp, udwordvalue
            mov eax, udtmp
        ELSE   
            mov eax, udwordvalue
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR udfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sdword$ MACRO sdwordvalue:req
    ; signed dword
    LOCAL buffer, sdtmp
    .data?
        sdtmp  SDWORD ?
        buffer BYTE   12 dup(?)
    IFNDEF sdfmt   
    .data   
        sdfmt BYTE "%ld", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        IF isregister(sdwordvalue)
            mov sdtmp, sdwordvalue
            mov eax, sdtmp
        ELSE           
            mov eax, sdwordvalue
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR sdfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xdword$ MACRO xdwordvalue:req
    ; unsigned hex dword
    LOCAL buffer, xdtmp
    .data?
        xdtmp  DWORD ?
        buffer BYTE  12 dup(?)
    IFNDEF xdfmt   
    .data   
        xdfmt BYTE "%lX", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        IF isregister(xdwordvalue)
            mov xdtmp, xdwordvalue
            mov eax, xdtmp
        ELSE           
            mov eax, xdwordvalue
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR xdfmt, eax
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
uqword$ MACRO uqwordvalue:req
    ; unsigned qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF uqwfmt   
    .data   
        uqwfmt BYTE "%I64u", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR uqwfmt, uqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
sqword$ MACRO sqwordvalue:req
    ; signed qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF sqwfmt   
    .data   
        sqwfmt BYTE "%I64d", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR sqwfmt, sqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
xqword$ MACRO xqwordvalue:req
    ; unsigned hex qword
    LOCAL buffer
    .data?
        buffer BYTE 20 dup(?)
    IFNDEF xqwfmt   
    .data   
        xqwfmt BYTE "%I64X", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR xqwfmt, xqwordvalue
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real4$ MACRO r4value:req
    LOCAL buffer, r8value, r4tmp
    .data?
        r4tmp   REAL4 ?
        r8value REAL8 ?
        buffer  BYTE  48 dup(?)
    IFNDEF r8fmt   
    .data
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        push   r4value
        pop    r4tmp
        finit
        fld    r4tmp
        fstp   r8value
        fwait
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real8$ MACRO r8value:req
    LOCAL buffer
    .data?
        buffer BYTE 320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt  BYTE "%lf", 0
    ENDIF   
    .code
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
real10$ MACRO r10value:req
    LOCAL buffer, r8value
    .data?
        r8value REAL8 ?
        buffer  BYTE  320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        IF isregister(r10value)
            fld    r10value
        ELSE 
            finit
            fld    r10value
        ENDIF           
        fstp   r8value
        fwait
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
;; ----------------------------------------------
;; ----------------------------------------------
printf MACRO pszFmt, args:VARARG
    IFB <args>
        IFB <pszFmt>
            invoke crt_printf, chr$(13,10)
        ELSE   
            invoke crt_printf, pszFmt
        ENDIF
    ELSE
        invoke crt_printf, pszFmt, args
    ENDIF   
ENDM   
;------------------------------------------------------------
WaitKey MACRO
    printf chr$(13, 10, "Press any key to continue...")
    call wait_key
    printf
ENDM
;------------------------------------------------------------

.DATA
       
    ubyMax BYTE   255                        ; UCHAR_MAX
    ubyMin BYTE     0                        ; UCHAR_MIN
   
    sbyMax SBYTE  127                        ; CHAR_MAX
    sbyMin SBYTE -128                        ; CHAR_MIN
   
    uwdMax WORD   65535                      ; USHRT_MAX
    uwdMin WORD       0                      ; USHRT_MIN
   
    swdMax SWORD  32767                      ; SHRT_MAX
    swdMin SWORD -32768                      ; SHRT_MIN
   
    udwMax DWORD   4294967295                ; ULONG MAX
    udwMin DWORD            0                ; ULONG_MIN
   
    sdwMax SDWORD  2147483647                ; LONG_MAX
    sdwMin SDWORD -2147483648                ; LONG_MIN
   
    uqwMax QWORD 18446744073709551615        ; _UI64_MAX
    uqwMin QWORD                    0        ; _UI64_MIN
   
    sqwMax QWORD  9223372036854775807        ; _I64_MAX
    sqwMin QWORD -9223372036854775808        ; _I64_MIN
   
    r4Max  REAL4   3.402823466E+38           ; FLT_MAX
    r4Min  REAL4  -1.175494351E-38           ; FLT_MIN
   
    r8Max  REAL8   1.7976931348623158E+308   ; DBL_MAX
    r8Min  REAL8  -2.2250738585072014E-308   ; DBL_MIN
   
    r10Max REAL10  1.7976931348623158E+308   ; LDBL_MAX ( = DBL_MAX)
    r10Min REAL10 -2.2250738585072014E-308   ; LDBL_MIN ( = DBL_MIN)
       
.CODE

start:
   
    printf SADD("Memory variables",10)
    printf SADD("================",10,10)
   
    printf SADD("ubyte$(UCHAR_MAX)  = %s",10), ubyte$(ubyMax)
    printf SADD("ubyte$(UCHAR_MIN)  = %s",10), ubyte$(ubyMin)
    printf
    printf SADD("sbyte$(CHAR_MAX)   = %s",10), sbyte$(sbyMax)
    printf SADD("sbyte$(CHAR_MIN)   = %s",10), sbyte$(sbyMin)
    printf
    printf SADD("xbyte$(UCHAR_MAX)  = %s",10), xbyte$(ubyMax)
    printf SADD("xbyte$(UCHAR_MIN)  = %s",10), xbyte$(ubyMin)
    printf
    printf SADD("uword$(USHRT_MAX)  = %s",10), uword$(uwdMax)
    printf SADD("uword$(USHRT_MIN)  = %s",10), uword$(uwdMin)
    printf
    printf SADD("sword$(SHRT_MAX)   = %s",10), sword$(swdMax)
    printf SADD("sword$(SHRT_MIN)   = %s",10), sword$(swdMin)
    printf
    printf SADD("xword$(USHRT_MAX)  = %s",10), xword$(uwdMax)
    printf SADD("xword$(USHRT_MIN)  = %s",10), xword$(uwdMin)
    printf
    printf SADD("udword$(ULONG_MAX) = %s",10), udword$(udwMax)
    printf SADD("udword$(ULONG_MIN) = %s",10), udword$(udwMin)
    printf
    printf SADD("sdword$(LONG_MAX)  = %s",10), sdword$(sdwMax)
    printf SADD("sdword$(LONG_MIN)  = %s",10), sdword$(sdwMin)
    printf 
    printf SADD("xdword$(ULONG_MAX) = %s",10), xdword$(udwMax)
    printf SADD("xdword$(ULONG_MIN) = %s",10), xdword$(udwMin)
    printf
    printf SADD("uqword$(_UI64_MAX) = %s",10), uqword$(uqwMax)
    printf SADD("uqword$(_UI64_MIN) = %s",10), uqword$(uqwMin)
    printf
    printf SADD("sqword$(_I64_MAX)  = %s",10), sqword$(sqwMax)
    printf SADD("sqword$(_I64_MIN)  = %s",10), sqword$(sqwMin)
    printf
    printf SADD("xqword$(_UI64_MAX) = %s",10), xqword$(uqwMax)
    printf SADD("xqword$(_UI64_MIN) = %s",10), xqword$(uqwMin)
    printf
    printf SADD("real4$(FLT_MAX)    = %s",10), real4$(r4Max)
    printf SADD("real4$(FLT_MIN)    = %s",10), real4$(r4Min)
    printf
    printf SADD("real8$(DBL_MAX)    = %s",10), real8$(r8Max)
    printf SADD("real8$(DBL_MIN)    = %s",10), real8$(r8Min)
    printf
    printf SADD("real10$(LDBL_MAX) = %s",10), real10$(r10Max)
    printf SADD("real10$(LDBL_MIN) = %s",10), real10$(r10Min)
    printf
   
    printf SADD("Register variables",10)
    printf SADD("==================",10,10)
   
    mov al, ubyMax
    printf SADD("ubyte$(UCHAR_MAX)  = %s",10), ubyte$(al)
    mov al, ubyMin
    printf SADD("ubyte$(UCHAR_MIN)  = %s",10), ubyte$(al)
    printf
    mov al, sbyMax
    printf SADD("sbyte$(CHAR_MAX)   = %s",10), sbyte$(al)
    mov al, sbyMin
    printf SADD("sbyte$(CHAR_MIN)   = %s",10), sbyte$(al)
    printf
    mov al, ubyMax
    printf SADD("xbyte$(UCHAR_MAX)  = %s",10), xbyte$(al)
    mov al, ubyMin
    printf SADD("xbyte$(UCHAR_MIN)  = %s",10), xbyte$(al)
    printf

    mov ax, uwdMax
    printf SADD("uword$(USHRT_MAX)  = %s",10), uword$(ax)
    mov ax, uwdMin
    printf SADD("uword$(USHRT_MIN)  = %s",10), uword$(ax)
    printf
    mov ax, swdMax
    printf SADD("sword$(SHRT_MAX)   = %s",10), sword$(ax)
    mov ax, swdMin
    printf SADD("sword$(SHRT_MIN)   = %s",10), sword$(ax)
    printf
    mov ax, uwdMax
    printf SADD("xword$(USHRT_MAX)  = %s",10), xword$(ax)
    mov ax, uwdMin
    printf SADD("xword$(USHRT_MIN)  = %s",10), xword$(ax)
    printf

    mov eax, udwMax
    printf SADD("udword$(ULONG_MAX) = %s",10), udword$(eax)
    mov eax, udwMin
    printf SADD("udword$(ULONG_MIN) = %s",10), udword$(eax)
    printf
    mov eax, sdwMax
    printf SADD("sdword$(LONG_MAX)  = %s",10), sdword$(eax)
    mov eax, sdwMin
    printf SADD("sdword$(LONG_MIN)  = %s",10), sdword$(eax)
    printf 
    mov eax, udwMax
    printf SADD("xdword$(ULONG_MAX) = %s",10), xdword$(eax)
    mov eax, udwMin
    printf SADD("xdword$(ULONG_MIN) = %s",10), xdword$(eax)
    printf

    mov esi, OFFSET uqwMax
    mov edx, [esi+4]
    mov eax, [esi+0]
    printf SADD("uqword$(_UI64_MAX) = %s",10), uqword$(edx::eax)
    mov esi, OFFSET uqwMin
    mov edx, [esi+4]
    mov eax, [esi+0]
    printf SADD("uqword$(_UI64_MIN) = %s",10), uqword$(edx::eax)
    printf
    mov esi, OFFSET sqwMax
    mov edx, [esi+4]
    mov eax, [esi+0]
    printf SADD("sqword$(_I64_MAX)  = %s",10), sqword$(edx::eax)
    mov esi, OFFSET sqwMin
    mov edx, [esi+4]
    mov eax, [esi+0]
    printf SADD("sqword$(_I64_MIN)  = %s",10), sqword$(edx::eax)
    printf
    mov esi, OFFSET uqwMax
    mov edx, [esi+4]
    mov eax, [esi+0]       
    printf SADD("xqword$(_UI64_MAX) = %s",10), xqword$(edx::eax)
    mov esi, OFFSET uqwMin
    mov edx, [esi+4]
    mov eax, [esi+0]       
    printf SADD("xqword$(_UI64_MIN) = %s",10), xqword$(edx::eax)
    printf

    mov eax, r4Max
    printf SADD("real4$(FLT_MAX)    = %s",10), real4$(eax)
    mov eax, r4Min
    printf SADD("real4$(FLT_MIN)    = %s",10), real4$(eax)
    printf

    mov esi, OFFSET r8Max
    mov edx, [esi+4]
    mov eax, [esi+0]       
    printf SADD("real8$(DBL_MAX)    = %s",10), real8$(edx::eax)
    mov esi, OFFSET r8Min
    mov edx, [esi+4]
    mov eax, [esi+0]
    printf SADD("real8$(DBL_MIN)    = %s",10), real8$(edx::eax)
    printf

    finit
    fld r10Max
    printf SADD("real10$(LDBL_MAX)  = %s",10), real10$(ST(0))
    fstp st(0)
    fld r10Min
    printf SADD("real10$(LDBL_MIN)  = %s",10), real10$(ST(0))
    fstp st(0)
   
    WaitKey
         
    invoke ExitProcess, 0

end start


Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 15, 2005, 08:57:30 AM
Greg,

I found that ml 6.14 was broken on the TYPE return size for a BYTE where ml 7.0 is not so I put this macro together to be reliable on both.


  ; **********************************
  ; test if an argument is an integer
  ; register and return its byte size
  ; if it is else return zero if it
  ; is not a register.
  ; **********************************
    iregsize MACRO item
      LOCAL rv
      rv = 0
      for arg,<eax,ebx,ecx,edx,esp,ebp,esi,edi>
        IFIDNI <arg>,<item>
          rv = 4
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF
      for arg,<al,ah,bl,bh,cl,ch,dl,dh>
        IFIDNI <arg>,<item>
          rv = 1
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF
      for arg,<ax,bx,cx,dx,sp,bp,si,di>
        IFIDNI <arg>,<item>
          rv = 2
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF
      EXITM %rv
    ENDM
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 15, 2005, 06:31:10 PM
Hutch,

I am using ML 6.15, TYPE works correctly on byte sized memory variables but it fails on byte sized registers, it's the same as 6.14 I believe. I like the new macro.

I'm pretty happy with the sprintf macros posted above, if you have any suggestions for improvement or concerns, let me know.

Title: Re: Suggestion with MSVCRT code.
Post by: Phil on July 15, 2005, 06:36:44 PM
Will the new macro automatically handle upper-case registers like 'AL', 'BL', etc., or should we always use lower-case to use anything that uses these macros? Does the case dependency depend on the command line options that apply to variable names? The macro looks nice!
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 15, 2005, 07:41:40 PM
Phil,

IFIDNI is case insensitive so the macro is case insensitive.


Hutch,

I was playing around with your macro, I extended it, and this works. :dance:


;------------------------------------------------------------
; **********************************
; test if an argument is a register
; and return its byte size if it is
; else return zero if it is not a
; register.
; **********************************
iregsize MACRO item
  LOCAL rv
  rv = 0
  for arg,<eax,ebx,ecx,edx,esp,ebp,esi,edi>
    IFIDNI <arg>,<item>
      rv = 4
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF
  for arg,<al,ah,bl,bh,cl,ch,dl,dh>
    IFIDNI <arg>,<item>
      rv = 1
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF
  for arg,<ax,bx,cx,dx,sp,bp,si,di>
    IFIDNI <arg>,<item>
      rv = 2
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF
  for arg,<edx::eax,ecx::ebx>
    IFIDNI <arg>,<item>
      rv = 8
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF 
  for arg,<st,st(0),st(1),st(2),st(3),st(4),st(5),st(6),st(7)>
    IFIDNI <arg>,<item>
      rv = 10
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF 
  for arg,<mm0,mm1,mm2,mm3,mm4,mm5,mm6,mm7>
    IFIDNI <arg>,<item>
      rv = 8
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF   
  for arg,<xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7>
    IFIDNI <arg>,<item>
      rv = 16
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF     
  EXITM %rv
ENDM

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 16, 2005, 01:01:44 AM
Greg,

The mod looks good. I wonder if there will be any problems with alternative syntax on fp, mmx and xmm register names.

LATER :

I tweaked the version to handle both syntaxes, with or without brackets for the index on mm, xmm and st registers. It was starting to get a bit long so I did a length test on the arg and branched on the length which should prevent redundant code execution.


  ; ************************************
  ; Return a register size in BYTES or *
  ; 0 if the arguent is not a register *
  ; ************************************
    regsize MACRO item
      LOCAL rv,ln
      rv = 0
      ln SIZESTR <item>

      IF ln EQ 2
        goto two
      ELSEIF ln EQ 3
        goto three
      ELSEIF ln EQ 4
        goto four
      ELSEIF ln EQ 5
        goto five
      ELSEIF ln EQ 6
        goto six
      ELSE
        goto notreg
      ENDIF

    :two
      for arg,<al,ah,bl,bh,cl,ch,dl,dh>
        IFIDNI <arg>,<item>
          rv = 1
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF

      for arg,<ax,bx,cx,dx,sp,bp,si,di>
        IFIDNI <arg>,<item>
          rv = 2
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF
      goto notreg

    :three
      for arg,<eax,ebx,ecx,edx,esp,ebp,esi,edi>
        IFIDNI <arg>,<item>
          rv = 4
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF

      for arg,<st0,st1,st2,st3,st4,st5,st6,st7>
        IFIDNI <arg>,<item>
          rv = 10
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF

      for arg,<mm0,mm1,mm2,mm3,mm4,mm5,mm6,mm7>
        IFIDNI <arg>,<item>
          rv = 8
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF
      goto notreg

    :four
      for arg,<xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7>
        IFIDNI <arg>,<item>
          rv = 16
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF
      goto notreg

    :five
      for arg,<mm(0),mm(1),mm(2),mm(3),mm(4),mm(5),mm(6),mm(7)>
        IFIDNI <arg>,<item>
          rv = 8
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF

      for arg,<st(0),st(1),st(2),st(3),st(4),st(5),st(6),st(7)>
        IFIDNI <arg>,<item>
          rv = 10
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF
      goto notreg

    :six
      for arg,<xmm(0),xmm(1),xmm(2),xmm(3),xmm(4),xmm(5),xmm(6),xmm(7)>
        IFIDNI <arg>,<item>
          rv = 16
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF

    :notreg
      EXITM %rv
    ENDM
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 16, 2005, 03:20:50 AM
Hutch,

Oops. :red  It looks like you have to list them all out.


; **********************************
; test if an argument is a register
; and return its byte size if it is
; else return zero if it is not a
; register.
; **********************************
iregsize MACRO item
  LOCAL rv
  rv = 0
  for arg,<eax,ebx,ecx,edx,esp,ebp,esi,edi>
    IFIDNI <arg>,<item>
      rv = 4
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF
  for arg,<al,ah,bl,bh,cl,ch,dl,dh>
    IFIDNI <arg>,<item>
      rv = 1
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF
  for arg,<ax,bx,cx,dx,sp,bp,si,di>
    IFIDNI <arg>,<item>
      rv = 2
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF
  for arg,<edx::eax,ecx::ebx>
    IFIDNI <arg>,<item>
      rv = 8
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF 
  for arg,<st(0),st(1),st(2),st(3),st(4),st(5),st(6),st(7),st,st0,st1,st2,st3,st4,st5,st6,st7>
    IFIDNI <arg>,<item>
      rv = 10
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF 
  for arg,<mm0,mm1,mm2,mm3,mm4,mm5,mm6,mm7,mm,mm(0),mm(1),mm(2),mm(3),mm(4),mm(5),mm(6),mm(7)>
    IFIDNI <arg>,<item>
      rv = 8
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF   
  for arg,<xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7,xmm,xmm(0),xmm(1),xmm(2),xmm(3),xmm(4),xmm(5),xmm(6),xmm(7)>
    IFIDNI <arg>,<item>
      rv = 16
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF     
  EXITM %rv
ENDM




Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 16, 2005, 03:50:18 AM
I think I forgot to put the EDX::EAX register pair test but the idea was to try and reduce the amount of macro code so that it did not get too slow. That was the idea of the length test first so you could branch a lot closewr than running them all until you found a match.

Here is the test piece I used.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
       
comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

  ; ************************************
  ; Return a register size in BYTES or *
  ; 0 if the arguent is not a register *
  ; ************************************
    regsize MACRO item
      LOCAL rv,ln
      rv = 0
      ln SIZESTR <item>

      IF ln EQ 2
        goto two
      ELSEIF ln EQ 3
        goto three
      ELSEIF ln EQ 4
        goto four
      ELSEIF ln EQ 5
        goto five
      ELSEIF ln EQ 6
        goto six
      ELSE
        goto notreg
      ENDIF

    :two
      for arg,<al,ah,bl,bh,cl,ch,dl,dh>
        IFIDNI <arg>,<item>
          rv = 1
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF

      for arg,<ax,bx,cx,dx,sp,bp,si,di>
        IFIDNI <arg>,<item>
          rv = 2
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF
      goto notreg

    :three
      for arg,<eax,ebx,ecx,edx,esp,ebp,esi,edi>
        IFIDNI <arg>,<item>
          rv = 4
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF

      for arg,<st0,st1,st2,st3,st4,st5,st6,st7>
        IFIDNI <arg>,<item>
          rv = 10
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF

      for arg,<mm0,mm1,mm2,mm3,mm4,mm5,mm6,mm7>
        IFIDNI <arg>,<item>
          rv = 8
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF
      goto notreg

    :four
      for arg,<xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7>
        IFIDNI <arg>,<item>
          rv = 16
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF
      goto notreg

    :five
      for arg,<mm(0),mm(1),mm(2),mm(3),mm(4),mm(5),mm(6),mm(7)>
        IFIDNI <arg>,<item>
          rv = 8
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF

      for arg,<st(0),st(1),st(2),st(3),st(4),st(5),st(6),st(7)>
        IFIDNI <arg>,<item>
          rv = 10
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF
      goto notreg

    :six
      for arg,<xmm(0),xmm(1),xmm(2),xmm(3),xmm(4),xmm(5),xmm(6),xmm(7)>
        IFIDNI <arg>,<item>
          rv = 16
          EXITM
        ENDIF
      ENDM
      IF rv NE 0
        EXITM %rv
      ENDIF

    :notreg
      EXITM %rv
    ENDM


    .code

start:
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call main
    inkey
    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc

    % echo regsize(al)
    % echo regsize(ah)

    % echo regsize(ax)
    % echo regsize(bx)

    % echo regsize(eax)
    % echo regsize(edi)

    % echo regsize(mm0)
    % echo regsize(mm(4))

    % echo regsize(st0)
    % echo regsize(st(5))

    % echo regsize(xmm7)
    % echo regsize(xmm(3))

    ret

main endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 16, 2005, 04:48:13 AM
Hutch,

I missed the 'LATER' part. Yes, it was getting pretty large, the length test helps a lot.

MASM macros are amazing, I never did a lot with them before. I'm just starting to realize what all can be done with them. Thanks for prodding me into learning more about them.

Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 16, 2005, 09:01:02 PM
I'm getting about sick of these sprintf conversion macros, I'm sure everyone else is too. :wink  But I want to get them right.

Here is the latest update, I hope I'm done with these.


.586
.MODEL FLAT, stdcall
option casemap:none

include c:\masm32\include\windows.inc

include c:\masm32\include\kernel32.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\masm32.inc
include c:\masm32\include\msvcrt.inc

include c:\masm32\macros\macros.asm

includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\masm32.lib
includelib c:\masm32\lib\msvcrt.lib

; ************************************
; Return a register size in BYTES or *
; 0 if the arguent is not a register *
; ************************************
regsize MACRO item
  LOCAL rv,ln
  rv = 0
  ln SIZESTR <item>

  IF ln EQ 2
    goto two
  ELSEIF ln EQ 3
    goto three
  ELSEIF ln EQ 4
    goto four
  ELSEIF ln EQ 5
    goto five
  ELSEIF ln EQ 6
    goto six
  ELSEIF ln EQ 8
    goto eight
  ELSE
    goto notreg
  ENDIF

:two
  for arg,<al,ah,bl,bh,cl,ch,dl,dh>
    IFIDNI <arg>,<item>
      rv = 1
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF

  for arg,<ax,bx,cx,dx,sp,bp,si,di>
    IFIDNI <arg>,<item>
      rv = 2
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF
  goto notreg

:three
  for arg,<eax,ebx,ecx,edx,esp,ebp,esi,edi>
    IFIDNI <arg>,<item>
      rv = 4
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF

  for arg,<st0,st1,st2,st3,st4,st5,st6,st7>
    IFIDNI <arg>,<item>
      rv = 10
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF

  for arg,<mm0,mm1,mm2,mm3,mm4,mm5,mm6,mm7>
    IFIDNI <arg>,<item>
      rv = 8
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF
  goto notreg

:four
  for arg,<xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7>
    IFIDNI <arg>,<item>
      rv = 16
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF
  goto notreg

:five
  for arg,<mm(0),mm(1),mm(2),mm(3),mm(4),mm(5),mm(6),mm(7)>
    IFIDNI <arg>,<item>
      rv = 8
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF

  for arg,<st(0),st(1),st(2),st(3),st(4),st(5),st(6),st(7)>
    IFIDNI <arg>,<item>
      rv = 10
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF
  goto notreg

:six
  for arg,<xmm(0),xmm(1),xmm(2),xmm(3),xmm(4),xmm(5),xmm(6),xmm(7)>
    IFIDNI <arg>,<item>
      rv = 16
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF
 
:eight
  for arg,<edx::eax,ecx::ebx>
    IFIDNI <arg>,<item>
      rv = 8
      EXITM
    ENDIF
  ENDM
  IF rv NE 0
    EXITM %rv
  ENDIF 

:notreg
  EXITM %rv
ENDM
;---------------------------------------------------
issize MACRO var:req, bytes:req
    LOCAL rv
    rv = regsize(var)
    IFE rv ; if not a register use SIZE
        IF SIZE var EQ bytes
            EXITM <1>
        ELSE
            EXITM <0>
        ENDIF
    ELSE   ; it's a register       
        IF rv EQ bytes
            EXITM <1>       
        ELSE
            EXITM <0>
        ENDIF   
    ENDIF
ENDM
; ----------------------------------------------
isregister MACRO var:req
    IF regsize(var)
        EXITM <1>
    ELSE
        EXITM <0>
    ENDIF   
ENDM   
; ----------------------------------------------
ubyte$ MACRO ubytevalue:req
    ;; unsigned byte
    LOCAL buffer, ubtmp
    .data?
        ubtmp  BYTE ?
        buffer BYTE 4 dup(?)
    IFNDEF ubfmt   
    .data   
        ubfmt  BYTE "%hhu", 0
    ENDIF   
    .code
        IFE issize(ubytevalue, 1)
            echo ----------------------
            echo ubyte$ - requires BYTE
            echo ----------------------
            .ERR
        ENDIF               
        mov    buffer[0], 0
        IF isregister(ubytevalue)
            mov   ubtmp, ubytevalue
            movzx eax, ubtmp
        ELSE
            mov   al, ubytevalue
            movzx eax, al
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR ubfmt, eax
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
sbyte$ MACRO sbytevalue:req
    ;; signed byte
    LOCAL buffer, sbtmp
    .data?
        sbtmp  SBYTE ?
        buffer BYTE  8 dup(?)
    IFNDEF sbfmt     
    .data   
        sbfmt  BYTE "%hhd", 0
    ENDIF   
    .code
        IFE issize(sbytevalue, 1)
            echo -----------------------
            echo sbyte$ - requires SBYTE
            echo -----------------------
            .ERR
        ENDIF               
        mov    buffer[0], 0
        IF isregister(sbytevalue)
            mov   sbtmp, sbytevalue
            movsx eax, sbtmp
        ELSE     
            mov   al, sbytevalue
            movsx eax, al
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR sbfmt, eax
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
xbyte$ MACRO xbytevalue:req
    ;; unsigned hex byte
    LOCAL buffer, xbtmp
    .data?
        xbtmp  BYTE ?
        buffer BYTE 4 dup(?)
    IFNDEF xbfmt   
    .data   
        xbfmt  BYTE "%hhX", 0
    ENDIF   
    .code
        IFE issize(xbytevalue, 1)
            echo ----------------------
            echo xbyte$ - requires BYTE
            echo ----------------------
            .ERR
        ENDIF               
        mov buffer[0], 0
        IF isregister(xbytevalue)
            mov   xbtmp, xbytevalue
            movzx eax, xbtmp
        ELSE
            mov   al, xbytevalue
            movzx eax, al
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR xbfmt, eax
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
uword$ MACRO uwordvalue:req
    ;; unsigned word
    LOCAL buffer, uwtmp
    .data?
        uwtmp  WORD ?
        buffer BYTE 8 dup(?)
    IFNDEF uwfmt   
    .data   
        uwfmt  BYTE "%hu", 0
    ENDIF   
    .code
        IFE issize(uwordvalue, 2)
            echo ----------------------
            echo uword$ - requires WORD
            echo ----------------------
            .ERR
        ENDIF           
        mov   buffer[0], 0
        IF isregister(uwordvalue)
            mov   uwtmp, uwordvalue
            movzx eax, uwtmp
        ELSE       
            mov   ax, uwordvalue
            movzx eax, ax
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR uwfmt, eax
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
sword$ MACRO swordvalue:req
    ;; signed word
    LOCAL buffer, swtmp
    .data?
        swtmp  SWORD ?
        buffer BYTE  8 dup(?)
    IFNDEF swfmt   
    .data   
        swfmt  BYTE "%hd", 0
    ENDIF   
    .code
        IFE issize(swordvalue, 2)
            echo -----------------------
            echo sword$ - requires SWORD
            echo -----------------------
            .ERR
        ENDIF           
        mov   buffer[0], 0
        IF isregister(swordvalue)
            mov   swtmp, swordvalue
            movsx eax, swtmp
        ELSE   
            mov   ax, swordvalue
            movsx eax, ax
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR swfmt, eax
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
xword$ MACRO xwordvalue:req
    ;; unsigned hex word
    LOCAL buffer, xwtmp
    .data?
        xwtmp  WORD ?
        buffer BYTE 8 dup(?)
    IFNDEF xwfmt   
    .data   
        xwfmt  BYTE "%hX", 0
    ENDIF   
    .code
        IFE issize(xwordvalue, 2)
            echo ----------------------
            echo xword$ - requires WORD
            echo ----------------------
            .ERR
        ENDIF       
        mov   buffer[0], 0
        IF isregister(xwordvalue)
            mov   xwtmp, xwordvalue
            movzx eax, xwtmp
        ELSE               
            mov   ax, xwordvalue
            movzx eax, ax
        ENDIF   
        invoke crt_sprintf, ADDR buffer, ADDR xwfmt, eax
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
udword$ MACRO udwordvalue:req
    ;; unsigned dword
    LOCAL buffer
    .data?
        buffer BYTE  12 dup(?)
    IFNDEF udfmt   
    .data   
        udfmt  BYTE "%lu", 0
    ENDIF   
    .code
        IFE issize(udwordvalue, 4)
            echo ------------------------
            echo udword$ - requires DWORD
            echo ------------------------
            .ERR
        ENDIF   
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR udfmt, udwordvalue
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
sdword$ MACRO sdwordvalue:req
    ;; signed dword
    LOCAL buffer
    .data?
        buffer BYTE   12 dup(?)
    IFNDEF sdfmt   
    .data   
        sdfmt BYTE "%ld", 0
    ENDIF   
    .code
        IFE issize(sdwordvalue, 4)
            echo -------------------------
            echo sdword$ - requires SDWORD
            echo -------------------------
            .ERR
        ENDIF       
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR sdfmt, sdwordvalue
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
xdword$ MACRO xdwordvalue:req
    ;; unsigned hex dword
    LOCAL buffer
    .data?
        buffer BYTE  12 dup(?)
    IFNDEF xdfmt   
    .data   
        xdfmt BYTE "%lX", 0
    ENDIF   
    .code
        IFE issize(xdwordvalue, 4)
            echo ------------------------
            echo xdword$ - requires DWORD
            echo ------------------------
            .ERR
        ENDIF       
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR xdfmt, xdwordvalue
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
uqword$ MACRO uqwordvalue:req
    ;; unsigned qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF uqwfmt   
    .data   
        uqwfmt BYTE "%I64u", 0
    ENDIF   
    .code
        IFE issize(uqwordvalue, 8)
            echo ------------------------
            echo uqword$ - requires QWORD
            echo ------------------------
            .ERR
        ENDIF       
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR uqwfmt, uqwordvalue
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
sqword$ MACRO sqwordvalue:req
    ;; signed qword
    LOCAL buffer
    .data?
        buffer BYTE 24 dup(?)
    IFNDEF sqwfmt   
    .data   
        sqwfmt BYTE "%I64d", 0
    ENDIF   
    .code
        IFE issize(sqwordvalue, 8)
            echo ------------------------
            echo sqword$ - requires QWORD
            echo ------------------------
            .ERR
        ENDIF           
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR sqwfmt, sqwordvalue
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
xqword$ MACRO xqwordvalue:req
    ;; unsigned hex qword
    LOCAL buffer
    .data?
        buffer BYTE 20 dup(?)
    IFNDEF xqwfmt   
    .data   
        xqwfmt BYTE "%I64X", 0
    ENDIF   
    .code
        IFE issize(xqwordvalue, 8)
            echo ------------------------
            echo xqword$ - requires QWORD
            echo ------------------------
            .ERR
        ENDIF           
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR xqwfmt, xqwordvalue
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
real4$ MACRO r4value:req
    LOCAL buffer, r8value, r4tmp
    .data?
        r4tmp   REAL4 ?
        r8value REAL8 ?
        buffer  BYTE  48 dup(?)
    IFNDEF r8fmt   
    .data
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        IFE issize(r4value, 4)
            echo ------------------------
            echo real4$ - requires REAL4
            echo ------------------------
            .ERR
        ENDIF           
        IF isregister(r4value)
            push   r4value
            pop    r4tmp
            finit
            fld    r4tmp
        ELSE
            finit
            fld    r4value
        ENDIF   
        fstp   r8value
        fwait
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
real8$ MACRO r8value:req
    LOCAL buffer
    .data?
        buffer BYTE 320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt  BYTE "%lf", 0
    ENDIF   
    .code
        IFE issize(r8value, 8)
            echo ------------------------
            echo real8$ - requires REAL8
            echo ------------------------
            .ERR
        ENDIF           
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
real10$ MACRO r10value:req
    LOCAL buffer, r8value
    .data?
        r8value REAL8 ?
        buffer  BYTE  320 dup(?)
    IFNDEF r8fmt   
    .data   
        r8fmt   BYTE "%lf", 0
    ENDIF   
    .code
        IFE issize(r10value, 10)
            echo -------------------------
            echo real10$ - requires REAL10
            echo -------------------------
            .ERR
        ENDIF       
        fld    r10value
        fstp   r8value
        fwait
        mov    buffer[0], 0
        invoke crt_sprintf, ADDR buffer, ADDR r8fmt, r8value
        EXITM <OFFSET buffer>
ENDM
; ----------------------------------------------
; ----------------------------------------------
printf MACRO pszFmt, args:VARARG
    IFB <args>
        IFB <pszFmt>
            invoke crt_printf, SADD(10)
        ELSE   
            invoke crt_printf, pszFmt
        ENDIF
    ELSE
        invoke crt_printf, pszFmt, args
    ENDIF   
ENDM   
;------------------------------------------------------------

.DATA
       
    ubyMax BYTE   255                        ; UCHAR_MAX
    ubyMin BYTE     0                        ; UCHAR_MIN
   
    sbyMax SBYTE  127                        ; CHAR_MAX
    sbyMin SBYTE -128                        ; CHAR_MIN
   
    uwdMax WORD   65535                      ; USHRT_MAX
    uwdMin WORD       0                      ; USHRT_MIN
   
    swdMax SWORD  32767                      ; SHRT_MAX
    swdMin SWORD -32768                      ; SHRT_MIN
   
    udwMax DWORD   4294967295                ; ULONG MAX
    udwMin DWORD            0                ; ULONG_MIN
   
    sdwMax SDWORD  2147483647                ; LONG_MAX
    sdwMin SDWORD -2147483648                ; LONG_MIN
   
    uqwMax QWORD 18446744073709551615        ; _UI64_MAX
    uqwMin QWORD                    0        ; _UI64_MIN
   
    sqwMax QWORD  9223372036854775807        ; _I64_MAX
    sqwMin QWORD -9223372036854775808        ; _I64_MIN
   
    r4Max  REAL4   3.402823466E+38           ; FLT_MAX
    r4Min  REAL4  -1.175494351E-38           ; FLT_MIN
   
    r8Max  REAL8   1.7976931348623158E+308   ; DBL_MAX
    r8Min  REAL8  -2.2250738585072014E-308   ; DBL_MIN
   
    r10Max REAL10  1.7976931348623158E+308   ; LDBL_MAX ( = DBL_MAX)
    r10Min REAL10 -2.2250738585072014E-308   ; LDBL_MIN ( = DBL_MIN)
       
.CODE

start:
   
    printf SADD("Memory variables",10)
    printf SADD("================",10,10)
   
    printf SADD("ubyte$(UCHAR_MAX)  = %s",10), ubyte$(ubyMax)
    printf SADD("ubyte$(UCHAR_MIN)  = %s",10), ubyte$(ubyMin)
    printf
    printf SADD("sbyte$(CHAR_MAX)   = %s",10), sbyte$(sbyMax)
    printf SADD("sbyte$(CHAR_MIN)   = %s",10), sbyte$(sbyMin)
    printf
    printf SADD("xbyte$(UCHAR_MAX)  = %s",10), xbyte$(ubyMax)
    printf SADD("xbyte$(UCHAR_MIN)  = %s",10), xbyte$(ubyMin)
    printf
    printf SADD("uword$(USHRT_MAX)  = %s",10), uword$(uwdMax)
    printf SADD("uword$(USHRT_MIN)  = %s",10), uword$(uwdMin)
    printf
    printf SADD("sword$(SHRT_MAX)   = %s",10), sword$(swdMax)
    printf SADD("sword$(SHRT_MIN)   = %s",10), sword$(swdMin)
    printf
    printf SADD("xword$(USHRT_MAX)  = %s",10), xword$(uwdMax)
    printf SADD("xword$(USHRT_MIN)  = %s",10), xword$(uwdMin)
    printf
    printf SADD("udword$(ULONG_MAX) = %s",10), udword$(udwMax)
    printf SADD("udword$(ULONG_MIN) = %s",10), udword$(udwMin)
    printf
    printf SADD("sdword$(LONG_MAX)  = %s",10), sdword$(sdwMax)
    printf SADD("sdword$(LONG_MIN)  = %s",10), sdword$(sdwMin)
    printf 
    printf SADD("xdword$(ULONG_MAX) = %s",10), xdword$(udwMax)
    printf SADD("xdword$(ULONG_MIN) = %s",10), xdword$(udwMin)
    printf
    printf SADD("uqword$(_UI64_MAX) = %s",10), uqword$(uqwMax)
    printf SADD("uqword$(_UI64_MIN) = %s",10), uqword$(uqwMin)
    printf
    printf SADD("sqword$(_I64_MAX)  = %s",10), sqword$(sqwMax)
    printf SADD("sqword$(_I64_MIN)  = %s",10), sqword$(sqwMin)
    printf
    printf SADD("xqword$(_UI64_MAX) = %s",10), xqword$(uqwMax)
    printf SADD("xqword$(_UI64_MIN) = %s",10), xqword$(uqwMin)
    printf
    printf SADD("real4$(FLT_MAX)    = %s",10), real4$(r4Max)
    printf SADD("real4$(FLT_MIN)    = %s",10), real4$(r4Min)
    printf
    printf SADD("real8$(DBL_MAX)    = %s",10), real8$(r8Max)
    printf SADD("real8$(DBL_MIN)    = %s",10), real8$(r8Min)
    printf
    printf SADD("real10$(LDBL_MAX) = %s",10), real10$(r10Max)
    printf SADD("real10$(LDBL_MIN) = %s",10), real10$(r10Min)
    printf
   
    printf SADD("Register variables",10)
    printf SADD("==================",10,10)
   
    mov al, ubyMax
    printf SADD("ubyte$(UCHAR_MAX)  = %s",10), ubyte$(al)
    mov al, ubyMin
    printf SADD("ubyte$(UCHAR_MIN)  = %s",10), ubyte$(al)
    printf
    mov al, sbyMax
    printf SADD("sbyte$(CHAR_MAX)   = %s",10), sbyte$(al)
    mov al, sbyMin
    printf SADD("sbyte$(CHAR_MIN)   = %s",10), sbyte$(al)
    printf
    mov al, ubyMax
    printf SADD("xbyte$(UCHAR_MAX)  = %s",10), xbyte$(al)
    mov al, ubyMin
    printf SADD("xbyte$(UCHAR_MIN)  = %s",10), xbyte$(al)
    printf

    mov ax, uwdMax
    printf SADD("uword$(USHRT_MAX)  = %s",10), uword$(ax)
    mov ax, uwdMin
    printf SADD("uword$(USHRT_MIN)  = %s",10), uword$(ax)
    printf
    mov ax, swdMax
    printf SADD("sword$(SHRT_MAX)   = %s",10), sword$(ax)
    mov ax, swdMin
    printf SADD("sword$(SHRT_MIN)   = %s",10), sword$(ax)
    printf
    mov ax, uwdMax
    printf SADD("xword$(USHRT_MAX)  = %s",10), xword$(ax)
    mov ax, uwdMin
    printf SADD("xword$(USHRT_MIN)  = %s",10), xword$(ax)
    printf

    mov eax, udwMax
    printf SADD("udword$(ULONG_MAX) = %s",10), udword$(eax)
    mov eax, udwMin
    printf SADD("udword$(ULONG_MIN) = %s",10), udword$(eax)
    printf
    mov eax, sdwMax
    printf SADD("sdword$(LONG_MAX)  = %s",10), sdword$(eax)
    mov eax, sdwMin
    printf SADD("sdword$(LONG_MIN)  = %s",10), sdword$(eax)
    printf 
    mov eax, udwMax
    printf SADD("xdword$(ULONG_MAX) = %s",10), xdword$(eax)
    mov eax, udwMin
    printf SADD("xdword$(ULONG_MIN) = %s",10), xdword$(eax)
    printf

    mov esi, OFFSET uqwMax
    mov edx, [esi+4]
    mov eax, [esi+0]
    printf SADD("uqword$(_UI64_MAX) = %s",10), uqword$(edx::eax)
    mov esi, OFFSET uqwMin
    mov edx, [esi+4]
    mov eax, [esi+0]
    printf SADD("uqword$(_UI64_MIN) = %s",10), uqword$(edx::eax)
    printf
    mov esi, OFFSET sqwMax
    mov edx, [esi+4]
    mov eax, [esi+0]
    printf SADD("sqword$(_I64_MAX)  = %s",10), sqword$(edx::eax)
    mov esi, OFFSET sqwMin
    mov edx, [esi+4]
    mov eax, [esi+0]
    printf SADD("sqword$(_I64_MIN)  = %s",10), sqword$(edx::eax)
    printf
    mov esi, OFFSET uqwMax
    mov edx, [esi+4]
    mov eax, [esi+0]       
    printf SADD("xqword$(_UI64_MAX) = %s",10), xqword$(edx::eax)
    mov esi, OFFSET uqwMin
    mov edx, [esi+4]
    mov eax, [esi+0]       
    printf SADD("xqword$(_UI64_MIN) = %s",10), xqword$(edx::eax)
    printf

    mov eax, r4Max
    printf SADD("real4$(FLT_MAX)    = %s",10), real4$(eax)
    mov eax, r4Min
    printf SADD("real4$(FLT_MIN)    = %s",10), real4$(eax)
    printf

    mov esi, OFFSET r8Max
    mov edx, [esi+4]
    mov eax, [esi+0]       
    printf SADD("real8$(DBL_MAX)    = %s",10), real8$(edx::eax)
    mov esi, OFFSET r8Min
    mov edx, [esi+4]
    mov eax, [esi+0]
    printf SADD("real8$(DBL_MIN)    = %s",10), real8$(edx::eax)
    printf

    finit
    fld r10Max
    printf SADD("real10$(LDBL_MAX)  = %s",10), real10$(ST(0))
    fstp st(0)
    fld r10Min
    printf SADD("real10$(LDBL_MIN)  = %s",10), real10$(ST(0))
    fstp st(0)
   
    inkey SADD(10, "Press any key to exit...")
         
    invoke ExitProcess, 0

end start




[attachment deleted by admin]
Title: Re: Suggestion with MSVCRT code.
Post by: zooba on July 16, 2005, 11:13:57 PM
Wouldn't it be possible to test the register by using INSTR rather than a loop? Though you may lose the case-insensitivity then...

Also, with the really long code pieces, could they be put in zip files rather than code tags. I'm running a huge (1920x1200) screen and they're still annoying, so people with 1024x768 must be really angry at you ;)
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 16, 2005, 11:31:45 PM
zooba,

I would not worry too much about the problem, this work of Greg's will end up in the macros.asm file so it will not irritate anyone there. the "PHUN" part is I have to produce the documentation for them now that they are stable.
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 16, 2005, 11:59:39 PM
zooba,

Sorry, I'll stop posting the long code pieces. Point taken.

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 18, 2005, 02:08:38 AM
Greg,

Thanks for doing this much work, I know it has been time consuming but we have ended up with not only some very usiful and reliable conversions but some very useful macros for writing other more powerful macros. I now have them added to the reference version of macros.asm.

By getting enough preprocessor code up and running, the capacity has something to offer the more experienced programmer who is interested in extending the precision and accuracy of assembler coding in efficient and time effective ways. A reliable body of preprocessor code also makes the lead time from entry to production with programmers learning assembler programming a lot shorter.
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 18, 2005, 03:40:04 AM
Hutch,

You are welcome, I enjoy writing this stuff, and I am pleased you found it good enough to include in the MASM32 macros.

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 18, 2005, 04:30:09 AM
Greg,

I just want to try this idea out on you. I have so far renamed the sscanf macros to get their names shorter as follows. I was interested in the idea of using EXITM <OFFSET retval> so that these macros could be used like functions and make them easier to use. Does this make sense to you ?


a2ub    PROTO pStr:PTR BYTE, pUb :PTR BYTE
a2sb    PROTO pStr:PTR BYTE, pSb :PTR SBYTE
h2ub    PROTO pStr:PTR BYTE, pUb :PTR BYTE
a2uw    PROTO pStr:PTR BYTE, pUw :PTR WORD
a2sw    PROTO pStr:PTR BYTE, pSw :PTR SWORD
h2uw    PROTO pStr:PTR BYTE, pUw :PTR WORD
a2ud    PROTO pStr:PTR BYTE, pUdw:PTR DWORD
a2sd    PROTO pStr:PTR BYTE, pSdw:PTR SDWORD
h2ud    PROTO pStr:PTR BYTE, pUdw:PTR DWORD
a2uq    PROTO pStr:PTR BYTE, pUqw:PTR QWORD
a2sq    PROTO pStr:PTR BYTE, pSqw:PTR QWORD
h2sq    PROTO pStr:PTR BYTE, pUqw:PTR QWORD
a2r4    PROTO pStr:PTR BYTE, pR4 :PTR REAL4
a2r8    PROTO pStr:PTR BYTE, pR8 :PTR REAL8
a2r10   PROTO pStr:PTR BYTE, pR10:PTR REAL10


PS: I like your avatar from the front cover of Aqualung, I have the CD on my workdesk.  :bg
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 18, 2005, 06:44:02 PM
Hutch,

Yes, it makes sense. The names were rather long. I converted one of the sscanf procedures to a macro, just to test the concept, but I never posted it, and I never got around to converting the rest. Looks good to me :U

I have fond memories of the time when the 'Aqualung' album came out. 
 
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 18, 2005, 10:09:11 PM
I removed unneeded 'tmp' variables from udword$, sdword$ and xdword$ in the sprintf macros posted above: http://www.masmforum.com/simple/index.php?topic=1851.msg17946#msg17946
 

Title: Re: Suggestion with MSVCRT code.
Post by: Codewarp on July 19, 2005, 05:17:26 AM
Hutch -

Do I understand this thread right--you are putting together a complete msvcrt.dll in masm source code, with all api's and (hopefully) a faster implementation?  Does this include a multi-threaded version as well??  If so, there is a lot of speed to be had in the multi-threaded memory heap allocator, as long as you can avoid using locks and critical sections, in favor of lock-free methods.  The locks in msvcrt heap calls account for 60-80% of the time it spends (and 20% on memory management).  Lock-free methods can eliminate most of that overhead, tripling allocation performance.  Many applications often operate at "heap-bound" performance levels, and better allocator performance can directly show up in running client applications.

I have written and use a complete general purpose memory allocator that is 15 times faster than the msvcrt.dll, and plan to extend it, using lock-free methods, coupled with local dynamic per-thread memory pools.  It would be cool if your code supported installable heap management, so that I could make my methods available through the standard heap management calls.  My code for this is in C++, and likely to stay that way, but it can provide and access any conceivable interface from its own dll.

Also, I cannot seem to find any description of what parts of the msvcrt codebase are finished and which pieces are still wanting.  Such a description would make it a lot easier for those of us who would to add to this project, to be able to know what is needed and wanted at any given time.
Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 19, 2005, 07:07:29 AM
Codewarp,

In the latest service pack for masm32 there is a utility that creates both an include fle for the MSVCRT dll and a library as well. MSVCRT is a "known" dll so it can be reliably used from win95b upwards and that was its appeal. The function count is about 730 functions. It sounds like you have some good design there but rewriting a DLL the size of MSVCRT is a very large task.

One of our members recently did some benchmarks on different memory allocation strategies and using the low fragmentation heap there were some performance advantages using it but the results were interesting, the ancient GlobalAlloc() was the fastest on large allocations where HeapAlloc() was faster on repeated small allocations. The big loser was OLE string memory tha used to be fast on win9x but was definitely off the pace on later NT based OS versions.
Title: Calling C Run-time Functions from MASM
Post by: GregL on July 19, 2005, 08:49:02 PM
Variable Argument Functions and Argument Promotion in C, and How it Applies to Calling C Run-Time Library Functions from MASM

Certain C Run-Time functions, such as 'printf' and 'scanf', will accept a variable number of arguments. Because there is no formal prototype for variable argument functions, 'default argument promotion' applies. For 'unsigned char', 'signed char', 'unsigned short' and  'signed short' arguments, the C compiler promotes the  arguments to either 'unsigned int' or 'signed int' before the variable argument function is called. Also, 'float' arguments are promoted to 'double' before the function is called.

Quote from: ANSI C StandardANSI 3.3.2.2: "If the expression that denotes the called function has a type that does not include a prototype, the integral promotions are performed on each argument and arguments that have type float are promoted to double. These are called the default argument promotions. If the number of arguments does not agree with the number of  parameters, the behavior is undefined."

So, in MASM, we must do the argument promotion ourselves, before calling a variable argument C function.  BYTE, SBYTE, WORD and SWORD arguments must be zero-extended or sign-extended to either a DWORD or SDWORD. A REAL4 must be converted to a REAL8 before calling a variable argument C function. A REAL10 must be converted to a REAL8 before calling a variable argument C function, this is explained in the following  MSDN excerpt.

Quote from: MSDNPrevious 16-bit versions of Microsoft C/C++ and Microsoft Visual C++ supported the long double,  80-bit precision data type. In Win32 programming, however, the long double data type maps to the  double, 64-bit precision data type. The Microsoft run-time library provides long double versions  of the math functions only for backward compatibility. The long double function prototypes are  identical to the prototypes for their double counterparts, except that the long double data type  replaces the double data type. The long double versions of these functions should not be used in  new code.

We can still use the REAL10 data type in MASM Win32 programming, but when calling a C Run-Time  function you must convert the REAL10 to a REAL8 before the call. I have heard the Intel C  compiler supports the REAL10 data type but we are using MSVCRT.DLL (Microsoft).
Title: Passing Strings to C Run-Time Library Functions from MASM
Post by: GregL on July 19, 2005, 11:22:24 PM
Passing Strings to C Run-Time Library Functions from MASM

If you pass a string that contains escape sequences ( \t \n \r)  to a C Run-Time Library function, like printf, from MASM, it doesn't work.

.586
.MODEL FLAT, stdcall
option casemap:none

include windows.inc

include kernel32.inc
include user32.inc
include masm32.inc
include msvcrt.inc

include c:\masm32\macros\macros.asm

includelib kernel32.lib
includelib user32.lib
includelib masm32.lib
includelib msvcrt.lib

.DATA

    count   DWORD 2
    String  BYTE  "\tThis is a string containing %d escape sequences\n", 0

.CODE

start:

    invoke crt_printf, ADDR String, count
   
    invoke ExitProcess, 0

end start


the output is:

\tThis is a string containing 2 escape sequences\n


The C compiler converts the escape sequences to their ASCII value before sending the string to the function. Here is an example.

C program:

#include <stdio.h>

int main(void)
{
    int count = 2;

    printf("\tThis is a string containing %d escape sequences\n", count);

    return 0;
}


Assembly listing of above C program:

; Listing generated by Microsoft (R) Optimizing Compiler Version 13.10.3077

    TITLE   test.c
    .386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT   SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT   ENDS
_DATA   SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA   ENDS
CONST   SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST   ENDS
_BSS    SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS    ENDS
$$SYMBOLS   SEGMENT BYTE USE32 'DEBSYM'
$$SYMBOLS   ENDS
_TLS    SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS    ENDS
FLAT    GROUP _DATA, CONST, _BSS
    ASSUME  CS: FLAT, DS: FLAT, SS: FLAT
endif

INCLUDELIB LIBC
INCLUDELIB OLDNAMES

_DATA   SEGMENT
$SG794  DB  09H, 'This is a string containing %d escape sequences', 0aH
    DB  00H
_DATA   ENDS
PUBLIC  _main
EXTRN   _printf:NEAR
; Function compile flags: /Odt
_TEXT   SEGMENT
_count$ = -4                        ; size = 4
_main   PROC NEAR
; File c:\documents and settings\gregory  lyon\local settings\temp\test.c
; Line 4
  00000 55       push    ebp
  00001 8b ec        mov     ebp, esp
  00003 51       push    ecx
; Line 5
  00004 c7 45 fc 02 00
    00 00        mov     DWORD PTR _count$[ebp], 2
; Line 7
  0000b 8b 45 fc     mov     eax, DWORD PTR _count$[ebp]
  0000e 50       push    eax
  0000f 68 00 00 00 00   push    OFFSET FLAT:$SG794
  00014 e8 00 00 00 00   call    _printf
  00019 83 c4 08     add     esp, 8
; Line 9
  0001c 33 c0        xor     eax, eax
; Line 10
  0001e 8b e5        mov     esp, ebp
  00020 5d       pop     ebp
  00021 c3       ret     0
_main   ENDP
_TEXT   ENDS
END


So, in MASM we need to convert the escape sequences to their ASCII values before passing a string to the C Run-Time function. This works.

.586
.MODEL FLAT, stdcall
option casemap:none

include windows.inc

include kernel32.inc
include user32.inc
include masm32.inc
include msvcrt.inc

include c:\masm32\macros\macros.asm

includelib kernel32.lib
includelib user32.lib
includelib masm32.lib
includelib msvcrt.lib

.DATA

    count   DWORD 2
    String  BYTE  9, "This is a string containing %d escape sequences", 10, 0

.CODE

start:

    invoke crt_printf, ADDR String, count
   
    invoke ExitProcess, 0

end start



the output is:

        This is a string containing 2 escape sequences


Note that the format specifier ( %d ) is passed the same as it is in C.

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on July 20, 2005, 09:08:36 AM
This test piece may solve the problem with any of the text functions that embed newline and tab characters. This is just a simple test piece to make sure it works but its probably able to be used as a general purpose string macro to give this support to any string display function that requires it.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    cprintf MACRO txt:VARARG
      LOCAL buffer,lbuf,rbuf,sln,flag1,tmp
      flag1 = 0
      buffer equ <>
      lbuf equ <>
      rbuf equ <>

      FORC char,<txt>
        IF flag1 NE 0
          IFIDN <char>,<n>
            buffer CATSTR buffer,<",13,10,">
            flag1 = 0
            goto lpend
          ENDIF
          IFIDN <char>,<t>
            buffer CATSTR buffer,<",9,">
            flag1 = 0
            goto lpend
          ENDIF
        ENDIF
        IFIDN <char>,<\>
          flag1 = 1
          goto lpend
        ENDIF
        buffer CATSTR buffer,<char>
    :lpend
      ENDM
        buffer CATSTR buffer,<,0,0,0>   ;; append trailing zeros
        cpos INSTR buffer,<"",>         ;; chomp off the first empty quotes & comma
        IF cpos EQ 1
          buffer SUBSTR buffer,4
        ENDIF
      :reloop
        sln SIZESTR buffer
        cpos INSTR buffer,<"",>
          IF cpos EQ 0
            goto done
          ENDIF
        lbuf SUBSTR buffer,1,cpos-1
        rbuf SUBSTR buffer,cpos+3
        buffer equ <>
        buffer CATSTR lbuf,rbuf
        goto reloop
      :done
        sln SIZESTR buffer
        buffer SUBSTR buffer,1,sln-4
        .data
          tmp db buffer
        .code
        print OFFSET tmp
    ENDM

    .code

start:
   
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    call main
    inkey
    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

main proc

    cprintf "\tThis is a\n\ttest\n\tof embedded tab\n\tand newline characters\n"

    ret

main endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on July 20, 2005, 04:01:14 PM
Hutch,

That's cool, I was thinking about writing a macro to do that. You beat me to it. So if a person wants to use C-style escape sequences, they can.  :thumbu

One thing I noticed about what the C compiler does is '\n' is replaced only with 10, and not with 13, 10. How about making '\n' = 10, '\r' = 13 in the macro? Not that it makes a great deal of difference, but it would match the C implementation.

Escape Sequences (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/eleme_18.asp)

Title: Re: Suggestion with MSVCRT code.
Post by: GregL on August 02, 2005, 07:57:27 PM
Hutch,

Did you convert the sscanf conversion procedures I wrote to macros? I got the impression you were doing that, so I never did it. If you didn't, I would be glad to do it.

I was working on a program today where a macro would work better than the procedure, it got me thinking about this.

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on August 03, 2005, 12:34:43 AM
Greg,

I have been a bit bogged down of late but I thought the sscanf code was a very good candidate for a set of macros that would compliment the other conversions you have already finished. I had a quick play with the naming for the complete set and using something like,


a = ascii
h = hex
fl = float or fp

2 = to

data size

sb = signed byte
ub = unsigned byte


A naming scheme of something like this makes te whole lot far easier to remember
etc ....

I was just a bit worried that the workload was a bit high when you have other stuff to do.
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on August 03, 2005, 05:02:03 AM
sscanf conversion macros.

Any suggestions for improvement are welcome.

(the test program requires the newest sprintf conversion macros).



[attachment deleted by admin]
Title: Re: Suggestion with MSVCRT code.
Post by: GregL on August 04, 2005, 04:14:33 AM
Concatenate multiple strings using strcat C Run-Time function.


.586
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE

include    msvcrt.inc
includelib msvcrt.lib

.CODE

strmulticat PROC C argcount:DWORD, pDest:PTR BYTE, pArgs:VARARG
    ; concatenates multiple strings
    ; uses strcat C Run-Time function
    xor eax, eax
    .WHILE argcount > 0
        push eax
        mov edx, pArgs[eax]
        invoke crt_strcat, pDest, edx
        pop eax
        dec argcount
        add eax, 4
    .ENDW
    mov eax, pDest
    ret
strmulticat ENDP

END   

Title: Re: Suggestion with MSVCRT code.
Post by: hutch-- on August 05, 2005, 12:23:29 PM
Greg,

Sorry to be a bit slow coming back. I just tested the sscanf mcros and they work fine in your test piece.  :U
Title: Re: Suggestion with MSVCRT code.
Post by: MichaelW on October 10, 2005, 07:33:42 PM
This is a test piece that I used to determine how to read the _HUGE value from MSVCRT.DLL, and verify exactly what the value is. The _HUGE value is returned in case of error by a number of the floating-point support routines. The macro is supposed to automate the testing of the return value. I avoided using the FPU to do the comparison because doing so (without complex code) would destroy the return value that the function left on the FPU stack. The code clears the sign bit because some of the functions return +/- HUGE_VAL, where the sign of HUGE_VAL matches the sign of the value that cannot be represented.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc

    dbl2bin PROTO :REAL8,:DWORD

    is_huge_val MACRO dbl
        push  edx
        mov   eax, _imp___HUGE
        mov   eax, [eax]
        cmp   eax, DWORD PTR dbl
        mov   eax, 0
        jne   @F
        mov   eax, _imp___HUGE
        mov   eax, [eax+4]
        mov   edx, DWORD PTR dbl+4
        and   edx, NOT 80000000h        ;; clear sign bit
        cmp   eax, edx
        mov   eax, 0
        jne   @F
        mov   eax, 1
      @@:
        pop   edx
        EXITM <eax>
    ENDM

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
      HUGE_VAL  REAL8 0.0
      binstr    db 65 dup(0)
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    mov   ebx,_imp___HUGE
    fld   REAL8 PTR [ebx]
    fstp  HUGE_VAL

    invoke crt_printf, chr$("%E",10,"%f",10), HUGE_VAL, HUGE_VAL

    invoke dbl2bin, HUGE_VAL, ADDR binstr
    print ADDR binstr,13,10
    print "seeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffff"
    print chr$(13,10)
    print ustr$(is_huge_val(HUGE_VAL)),13,10
    print ustr$(is_huge_val(HUGE_VAL+1)),13,10
   
    mov   eax, input(13,10,13,10,"Press enter to exit...")
    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

dbl2bin proc uses edi dbl:REAL8, ptrsz:DWORD
    mov   eax, DWORD PTR dbl+4
    mov   edi, ptrsz
    sub   edi, 1
    mov   ecx, 32
  @@:
    add   edi, 1
    xor   edx, edx
    shl   eax, 1                ; next bit -> carry flag
    adc   edx, '0'
    mov   [edi], dl
    sub   ecx, 1
    jnz   @B
    mov   eax, DWORD PTR dbl
    mov   ecx, 32
  @@:
    add   edi, 1
    xor   edx, edx
    shl   eax, 1                ; next bit -> carry flag
    adc   edx, '0'
    mov   [edi], dl
    sub   ecx, 1
    jnz   @B
    mov   BYTE PTR [ebx+1], 0   ; terminating null
    ret
dbl2bin endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start



Title: Re: Suggestion with MSVCRT code.
Post by: ollydbg on June 08, 2006, 01:18:12 AM
Needn't so many macros. Make it easier like this:

printf   PROTO   C :dword,:vararg
includelib msvcrt.lib
.data
fmt db "%s",0
str db "run",10,0
.code
start:
      invoke printf,offset fmt,offset str
      invoke ExitProcess,0
end start