Last active
August 12, 2022 06:00
-
-
Save deadpixi/8fb276a43f242bbce95177342d1b58d8 to your computer and use it in GitHub Desktop.
A UUIDv4 generator in REXX.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* A UUIDv4 generator. | |
* By [email protected] | |
* This should work with any ANSI REXX interpreter, | |
* and I *think* it would work with ARexx, but I | |
* haven't checked. | |
*/ | |
/* Store the 16 bytes of random data in a string called bits | |
* We will populate this using either using the RANDOM function | |
* or by reading from /dev/random, whichever the user requests. | |
*/ | |
bits = '' | |
/* Parse the argument to the program. We expect to be invoked | |
* either as | |
* | |
* generate-uuid RANDOM | |
* | |
* to generate a UUID pulling randomness from /dev/random, or | |
* like | |
* | |
* generate-uuid 393820 | |
* | |
* where the provided number is the seed for the internal | |
* RANDOM function. | |
* | |
* For testing purposes, being called with NULL will generate a | |
* NULL "random" UUID. | |
*/ | |
PARSE UPPER ARG mode | |
SELECT | |
WHEN mode = NULL THEN | |
CALL GenerateNull | |
WHEN mode = RANDOM THEN | |
CALL GenerateRandom | |
WHEN DATATYPE(mode) = NUM THEN | |
CALL GenerateSeeded mode | |
OTHERWISE | |
SAY "Expected random seed, RANDOM, or NULL" | |
EXIT 1 | |
END | |
/* Our string of bits is populated, so now we can the bits | |
* that specify the UUID variant and version. | |
* | |
* To do this, let's split the string into the parts that | |
* are random and the parts that are informational. This | |
* illustrates REXX's powerful PARSE instruction. | |
*/ | |
PARSE VAR bits first +48 version +4 mid +12 variant +2 rest | |
/* Recombine everything, specifying version and variant. | |
* Note that we use the explicit concatenation operator | |
* here. | |
*/ | |
bits = first || 0100 || mid || 10 || rest | |
/* Parse it out into the constituent bits. */ | |
PARSE VAR bits first +32 second +16 third +16 fourth +16 rest | |
/* And output the UUID. This uses REXX's automatic concatenation. | |
* Note that we can't have spaces around the quoted dashes, or | |
* else we'd have spaces in our output. | |
* | |
* Also note that ANSI REXX specifically guarantees that we don't | |
* suppress left-padding with zeroes when converting from binary | |
* to hex. If it didn't, we'd have to do zero padding on the left | |
* for each of the segments here. | |
*/ | |
SAY B2X(first)"-"B2X(second)"-"B2X(third)"-"B2X(fourth)"-"B2X(rest) | |
/* And we're done... */ | |
EXIT | |
/* Our procedure definitoions that get called above. These were | |
* factored out as a way to show how to create procedures in REXX; | |
* they equally could have been functions or just included inline | |
* above. | |
*/ | |
GenerateNull: PROCEDURE EXPOSE bits | |
bits = COPIES(0, 128) | |
RETURN | |
GenerateRandom: PROCEDURE EXPOSE bits | |
/* What to do on IO errors... */ | |
SIGNAL ON NOTREADY | |
/* Populate the bit string... */ | |
DO i = 1 TO 16 | |
bits = bits || X2B(C2X(CHARIN('/dev/random'))) | |
END | |
RETURN | |
GenerateSeeded: PROCEDURE EXPOSE bits | |
/* Grab our argument. */ | |
PARSE ARG seed | |
/* Seed the random number generator. */ | |
CALL RANDOM 1, 255, seed | |
/* Populate the bitstring... */ | |
DO i = 1 TO 16 | |
bits = bits || X2B(C2X(RANDOM(0, 255))) | |
END | |
RETURN | |
NOTREADY: | |
SAY "Error reading /dev/random" | |
EXIT |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment