Skip to content

Instantly share code, notes, and snippets.

@deadpixi
Last active August 12, 2022 06:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deadpixi/8fb276a43f242bbce95177342d1b58d8 to your computer and use it in GitHub Desktop.
Save deadpixi/8fb276a43f242bbce95177342d1b58d8 to your computer and use it in GitHub Desktop.
A UUIDv4 generator in REXX.
/* A UUIDv4 generator.
* By rob@frigidriver.com
* 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