Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

A little C code converted to Perl *HELP*

by regnab (Initiate)
on Nov 03, 2003 at 03:59 UTC ( [id://303996]=perlquestion: print w/replies, xml ) Need Help??

regnab has asked for the wisdom of the Perl Monks concerning the following question:

Hello Perlmonks community!

My name is Peter, i just signed up and posting the first time to seek the wisdom of the perkmonks community...

im not a novice perl coder, but today i got some ad code snippet of my company which i need to include into my application.

They send me the code in "C" , it is short and easy to readout... i tried the whole day but i wasnt successfull converting this code to Perl - since im not that familar with dwords and getdriveinformations!

This is what the complete "C" snipped code of it looks like:


char drivenamestr[32]; strcpy(drivenamestr, "C:\\"); DWORD sn=0, ignored1, ignored2; for (int drivename='C'; drivename<='Z'; drivename++) { drivenamestr[0]=drivename; if (GetVolumeInformation(drivenamestr, 0, 0, &sn, &ignored1, &ign +ored2,0, 0)) break; }; if (!sn) sn=0xE16E; sn^=0x35AF; srand(sn); volatile DWORD r32=0; for (int i=0; i<11; i++) { r32<<=15; r32|=rand(); }; DWORD generated_check=(rand()<<16) | rand(); char gcheck[64]; sprintf(gcheck, "%x", generated_check);


Many thx on any help - Help really appreciated...

Thanks!!

Yours, Peter.

Replies are listed 'Best First'.
Re: A little C code converted to Perl *HELP*
by BrowserUk (Patriarch) on Nov 03, 2003 at 05:06 UTC

    You can get access to the GetVolumeInformation() API via Win32API::File.

    The rest of it is almost a straight forward line for line conversion, though you might need to use bytes for the bit-twiddling. There is one bit that, as far as I am aware, there is no way to emulate in Perl.

    volatile DWORD r32=0; ...

    There isn't, and probably couldn't be, any equivalent to the volatile keyword in perl. And, unless the DWORD is truely volatile. ie. subject to change from outside of the scope of this piece of code, or the piece of code that the C-compiler can see when compiling this piece of code, then the declaration of r32, and the entire for loop that follows it is a comeplete waste of time, as r32 is never re-used in the snippet you have shown us. However, if it is volatile, then it would probably need to declared as extern as well.

    Similarly, the whole: Read the volume serial number from the first disk we can find, or use some arbitrary number (0xe16e) instead. Then use the serial number/arbitrary number, exclucive or'd with some other arbitrary number (0x35af) as a seed for the random number generator is, at best flaky, and at worst, totally pointless. That said, the perl's PRNG self seeds in a pretty well thought out way and use of srand is discouraged -- unless you actually want to create repeatable sequences.

    So, everything preceeding the volatile keyword in your snippet is redundant in a perl program and should be ignored.

    The for loop following the volatile keyword is pointless unless r32 is truely volatile, and if it is, you can't emulate that from perl. (Maybe with inline C or XS, but non-trivial!).

    That leaves the sprintf. All that does it create a string containing a 32-bit random number in hex, which it does by combining a 16-bit random number with a 32-bit one, which is a bit suspect anyway.

    So, assuming that gcheck is used somewhere, that can be translated to

    my $check = sprintf '%x', int rand( 0xffffffff ); ## Bad!! See [roger +]'s post below. my $check = sprintf '%x', int( rand(0xffff) )<<16 | int( rand( 0xffff +) ); ## Probably OK.

    That's it. As far as I can tell the whole lot can be reduced to that one line.

    Except the volatile r32, which is probably a piece of C-runtime global memory that is used to store the current/last random number returned by the C version of rand(), but the perl rand doesn't use that anyway, so there is no point in performing that piece of shenanigins either.

    That's it. One line!


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Hooray!
    Wanted!

      This is an excellent solution. However you probably want to do the assignment in two steps -
      my $check = sprintf '%x', int rand( 0xffff ); # first 16 bits $check .= sprintf '%x', int rand( 0xffff ); # second 16 bits
      Otherwise the last 16 bits of $check is always 0xffff, at least on my version of Perl.

        Good point++

        I should have checked that! I've amended the post.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        Hooray!
        Wanted!

      I'd never encountered the apparant 16-bit limitation of perl's built-in rand function. most random numbers I use are pretty small. Having fallen foul of of it, I went to CPAN to look for an alternative and found Math::Random::MT which emulates (and replaces if you choose) the built-in rand and srand functions 1-for-1, and doesn't suffer this limitation. I can't vouch for the randomness of it's output (yet), but given it's authorship, it bodes well.

      It uses XS, so you would need to compile it, (or download a compatible binary version AS 5.8) for your version of perl.


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail
      Hooray!
      Wanted!

        I'd never encountered the apparant 16-bit limitation of perl's built-in rand function.
        Hmm... I always thought it was 24 bits. Maybe not for perl?

        Anyway, this old TPJ article (from 1996) discusses rand() in a little more depth, including the repeat cycle, for which slavishly following up the example implementation, in ANSI C libraries, is to blame. That was then... things might have changed since then, depending on the agenda of the P5P.

Re: A little C code converted to Perl *HELP*
by Roger (Parson) on Nov 03, 2003 at 04:15 UTC
    GetVolumeInformation is a Windows API function. The following is the definition of the function -
    BOOL GetVolumeInformation( LPCTSTR lpRootPathName, // address of root directory of the file system LPTSTR lpVolumeNameBuffer, // address of name of the volume DWORD nVolumeNameSize, // length of lpVolumeNameBuffer LPDWORD lpVolumeSerialNumber, // address of volume serial number LPDWORD lpMaximumComponentLength, // address of system’s maximum filename length LPDWORD lpFileSystemFlags, // address of file system flags LPTSTR lpFileSystemNameBuffer, // address of name of file system DWORD nFileSystemNameSize // length of lpFileSystemNameBuffer );
    You could use the Win32::API module to access this Windows function.

    DWORD is a long integer, which is 32-bits in size (a WORD is 16 bits).

    Hope this would be of some help to you.

Re: A little C code converted to Perl *HELP*
by jonadab (Parson) on Nov 03, 2003 at 04:32 UTC

    Maybe you should tell us what the code *does*. I'd have a *much* easier time writing Perl code from scratch given a description in English of what it's supposed to do. I've taken a shot at reading the C, but my C is marginal in the extreme, so I very well could get something wrong here...

    As near as I can determine, all this code does is seed the random number generator. Correct me if I am mistaken (did I mention my C is marginal?), but that is the only effect I think it has. If that is the case, you can translate it into a comment that indicates that Perl does this automatically.

    If the C code is doing something more substantial, you'll have to tell us what it's doing, before we can tell you how to do that in Perl. We're _Perl_ gurus; many of us don't know any C at all. If you need help with C, this really isn't the best place to get it.


    $;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/
      yep i think you are right, would you mind give me this little perl code which will make a random gcodeid like the c script do... you would do me a world-big-favour ;))

        Oh, I almost missed that little part at the end with the sprintf...

        DWORD generated_check=(rand()<<16) | rand(); char gcheck[64]; sprintf(gcheck, "%x", generated_check);

        My C, as I said, is marginal, but if this is doing what I think it's doing, ...

        $gcheck = printf "%x", ((rand() << 16) | rand());

        I'm assuming here that the C << operator is a left shift just like in Perl, but that's a wild guess. I'm also assuming that rand with no args in C does the same thing as in Perl, which is also a guess. Like I said, my knowledge of C leaves something to be desired. I know what the Perl code does. (It prints "0" every time.) I'm guessing at the C code. Probably guessing wrong.


        $;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/
Re: A little C code converted to Perl *HELP*
by batkins (Chaplain) on Nov 03, 2003 at 04:16 UTC
    Well, figure out what it's supposed to do and then ask a specific question about that. I'm not really clear on what it's doing. It seems to be getting the serial number from the first drive with a letter between C: and Z:, modifying that number, and then using it to seed a random number generator. Then it does some bit-shifting and starts to pull some random numbers.

    The question is: what are you trying to do with this code? Give us a little information about the environment you're running this in and what you're trying to accomplish. Win32::DriveInfo seems like it will do most of what you want, but it's still not clear what the purpose of all this is.


    The computer can't tell you the emotional story. It can give you the exact mathematical design, but what's missing is the eyebrows. - Frank Zappa
      I need to run some application which the ad company send to me. But i need to call that Exe with the GCodeID as parameter behind it, which is generated with this code... I really dont get a clue to get this into perl but i try what you told me, maybe someone still have a fast code on this!
Re: A little C code converted to Perl *HELP*
by ysth (Canon) on Nov 03, 2003 at 06:14 UTC
    This is just a stab in the dark, but...

    Is this calculating some kind of security key to validate that you are an authorized user of their application? If so, they probably won't thank you for publicizing the code, and you may be unable to get it working in perl since a differently functioning rand library may be used than whatever it is that they have. Why are they sending you the code rather than asking for information on your drive setup and calculating the number for you? (Perhaps you are redistributing to an unknown setup?)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://303996]
Approved by Roger
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (4)
As of 2024-04-20 16:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found