#charset "us-ascii" #pragma once /* * Copyright (c) 1999, 2006 Michael J. Roberts * * This file is part of TADS 3 * * This header defines the tads-gen intrinsic function set. This function * set provides some miscellaneous functions, including data conversions, * object iteration, regular expressions, and state persistence operations. */ /* * The tads-gen function set. This set contains basic data manipulation * and miscellaneous utility functions. */ intrinsic 'tads-gen/030008' { /* * Get the type of the given value. This returns a TypeXxx value. */ dataType(val); /* * Get the given parameter to the current function. 'idx' is 1 for the * first argument in left-to-right order, 2 for the second, and so on. */ getArg(idx); /* * Get the first object in memory. If 'cls' is provided, we return the * first object of the given class; otherwise we return the first * object of any kind. 'flags' is an optional bitwise combination of * ObjXxx values, specifying whether classes, instances, or both are * desired. If this isn't specified, ObjAll is assumed. This is used * in conjunction with nextObj() to iterate over all objects in memory, * or all objects of a given class. */ firstObj(cls?, flags?); /* * Get the next object in memory after the given object, optionally of * the given class and optionally limiting to instances, classes, or * both. This is used to continue an iteration started with * firstObj(). */ nextObj(obj, cls?, flags?); /* * Random number generator (RNG) initialization. This selects and * initializes the random number generator algorithm used by rand(). * TADS provides several different RNG algorithms; each RNG has * different properties, so some applications might have reasons to * prefer a particular algorithm. For general purposes, any of them * should produce good results. * * The interpreter automatically makes a call to randomize() (the * no-arguments version) when it starts up, unless the user specifies * the "-norand" option when launching the interpreter. For most * programs, this means that you'll never have to make your own call to * randomize() - you can just call rand() when you need random numbers. * * This function performs several tasks, depending on how you invoke * it: * *. randomize() - selects the default RNG algorithm (ISAAC), and seeds *. the RNG with truly random data from the operating system. * *. randomize(nil) - retrieves the current state of the RNG. Returns *. a list: [id, state], where 'id' is the ID of the currently *. selected RNG algorithm, and 'state' is a value containing *. its internal state, which can be used in a later call to *. randomize([id, state]) to restore the RNG state. The 'state' *. value is opaque, meaning that it's not meant to be used *. directly; the only thing you should do with it it save it *. for later if you should want to restore this state later. * *. randomize([id, state]) - if you pass in a list that obtained from *. an earlier call to randomize(nil), the RNG will be returned *. to its state at the time of the randomize(nil) call. This *. selects the same RNG algorithm that was in effect then and *. restores the internal state of the generator. After calling *. this, a series of calls to rand() will return the same *. sequence of numbers that were returned after the call to *. randomize(nil). * *. randomize(id) - selects the RNG algorithm identified by 'id' *. (an RNG_Xxx value). This doesn't change the state of *. the generator; it simply selects the algorithm. * *. randomize(id, nil) - selects the RNG algorithm identified by *. 'id' (an RNG_Xxx value), and seeds the generator with *. truly random data obtained from the operating system. * *. randomize(id, val) - selects the RNG algorithm identified by *. 'id' (an RNG_Xxx value), and seeds the generator with *. the initial value 'val'. This can be either an integer *. value or a string; the preferred format varies by *. algorithm, but they'll all accept either format. After *. you set a given seed value, rand() will return a sequence *. of numbers that's repeatable every time you set the same *. seed value. This can be useful for things like testing, *. where you want a sequence of numbers that's statistically *. random, but which can be reproduced on demand. * * Most programs that require random numbers want a truly unpredictable * series of numbers - that is, numbers that have a statistically * random distribution, with no discernible patterns, and which will be * different every time the program is run. There are two separate * parts to this proposition, and they're handled by separate * functions. rand() fulfills the first part: it uses a mathematical * formula to generate a series of numbers that are statistically * distributed in a random fashion (for example, so that "1" occurs as * often as "10" or any other number, any given sequence of 2, 3, or * more numbers is equally likely, and so on: mathematicians have many * formal tests that RNGs must satisfy to be considered random.) * randomize() fulfills the second part, which is making sure that the * sequence of numbers is different every time you run the program. * The reason this second part is important is that rand() is by its * nature deterministic: it's defined entirely in terms of a formula, * so given the same initial conditions, it'll always crank out the * same sequence of numbers. The trick is to randomize its initial * conditions - and what makes it tricky is that we can't just turn to * rand(), since it's the thing we're trying to randomize! * * This is where the "seed" values come in. randomize() and * randomize(id, nil) ask the operating system for truly random data to * use for the initial conditions. The degree of entropy in this OS * seed data varies by system; some systems have better entropy sources * than others. But whatever the source, the seed data should be * different each time you run the program. randomize() feeds this * seed data into the RNG to set its initial conditions, so each time * you run, rand() will be starting from a different initial state. * This makes for a different series of numbers from rand() on each * run. * * Note that it's not necessary (or desirable) to call randomize() * every time you want a random number. Once you seed the RNG, rand() * is all you need to call. It can be slow to gather the true random * data that randomize() uses, since this sometimes requires * interacting with hardware devices or scanning large amounts of * system data. rand() is quite fast, since it just calculates a * number using a formula. Depending on the system, rand() might also * be more reliable at producing high volumes of statistically random * data than the OS sources. The operating system sources of true * entropy don't always change quickly, so it's better to use them * infrequently, such as just once at the start of program execution, * than to use them as a routine source of random numbers. * * The fixed seed values, with randomize(id, val), do something a * little different. Rather than making the RNG produce different * sequences on each run, a fixed seed makes rand() generate the same * series of numbers every time. The numbers will still be * statistically random, but each time you run the program, you'll get * the same seaquence. (The sequence is a function of the seed value. * You'll get a different sequence for each different seed value.) * * Why would you want a fixed series of rand() results? One big reason * is testing. One popular way to test software is regression testing, * where you run the program and compare its output to a reference * version that you know is correct. If there are no differences, you * know that changes you've made to the program since haven't broken * anything in the test script. Randomization interferes with this * kind of testing, because it makes the output different on each run - * it's useless to do a simple mechanical comparison of the new and old * output because they'll always differ. Fixed seeds to the rescue. * Using a fixed seed, you can still exercise the program's random * behavior, but the sequence of random behavior will repeat on every * run, so you run those regression comparisons after all. The really * great thing is that you don't have to make big changes to the * program if you want to switch between test mode and real randomness * - all you have to do is change the one call to randomize(). */ randomize(...); /* * Select a random number or a random value. This uses the current * random number algorithm as selected via randomize(). * * If no arguments are supplied, the result is a random integer * distributed evenly over the full range of the 32-bit integer type. * The result can be positive or negative. * * If exactly one argument is supplied, the result depends on the type * of the argument: * * - Integer: the function returns an integer from 0 to one less than * the argument value. For example, rand(10) returns a number from 0 * to 9 inclusive. * * - List: the function randomly selects one of the values from the * list and returns it. * * - String: the function generates a random string by replacing each * character of the argument string with a randomly chosen character, * selected from a specific range specified by the argument character. * For example, each 'a' in the input string is replaced by a random * lower-case letter from a to z, each 'A' is replaced by a capital * letter, and each 'd' is replaced by a random digit 0 to 9. See the * System Manual for the full list of the character codes. * * If more than one argument is supplied, the function randomly selects * one of the arguments and returns it. Note that this is an ordinary * function call, so all of the arguments are evaluated, triggering any * side effects of those evaluations. * * In all cases, the random numbers are uniformly distributed, meaning * that each possible return value has equal probability. */ rand(...); /* * Convert the given value to a string representation. 'val' can be an * integer, in which case it's converted to a string representation in * the numeric base given by 'radix' (which can be any value from 2 to * 36), or base 10 (decimal) if 'radix' is omitted; nil or true, in * which case the string 'nil' or 'true' is returned; a string, which * is returned unchanged; or a BigNumber, in which case the number is * converted to a string representation in the given radix; a list or * vector, in which case the individual elements are converted * recursively, then the results concatenated together into a string * with commas separating elements; or any of the built-in object types * with default string conversions (ByteArray, StringBuffer, FileName, * Date, TimeZone, FileName, etc). * * Note that when working with BigNumber values, you might prefer to * use BigNumber.formatString(), as that gives you more control over * the formatting style. * * 'radix' is only meaningful with numeric values (integers and * BigNumbers). For BigNumbers, only whole integer values can be * displayed in a non-decimal radix; if the number has a fractional * part, the radix will be ignored and the number will be shown in * decimal. * * 'isSigned' indicates whether or not the value should be treated as * "signed", meaning that negative values are represented with a "-" * sign followed by the absolute value. If 'isSigned' is nil, a * negative value won't be converted to its absolute value before being * displayed, but will instead be re-interpreted within its type system * as an unsigned value. For regular integers, this means that the * result depends on the native hardware storage format for negative * integers. Most modern hardware uses two's complement notation, * which represents -1 as 0xFFFFFFFF, -2 as 0xFFFFFFFE, etc. Most * types other than integer don't have distinct signed and unsigned * interpretations, so 'isSigned' isn't meaningful with most other * types. With BigNumber in particular, the only effect is to omit the * "-" sign for negative values. */ toString(val, radix?, isSigned?); /* * Convert the given value to an integer. * * If 'val' is a string, the function parses the string's contents as * an integer in the numeric base given by 'radix, which can be any * integer from 2 to 36. If 'radix' is omitted or nil, the default is * base 10 (decimal). The value is returned as an integer. If the * number represented by the string is too large for a 32-bit integer, * a numeric overflow error occurs. * * If 'val' is true, or the string 'true', the return value is 1. If * 'val' is nil, or the string 'nil', the return value is 0. Leading * and trailing spaces are ignored for these strings. * * If 'val' is a BigNumber value, the value is rounded to the whole * number, and returned as an integer value. A numeric overflow error * occurs if the number is out of range for a 32-bit integer. (If you * want to round a BigNumber to the nearest integer and get the result * as another BigNumber value, use the getWhole() method of the * BigNumber.) * * See also toNumber(), which can also parse floating point values and * whole numbers too large for the ordinary integer type. */ toInteger(val, radix?); /* * Get the current local time. * * If timeType is GetTimeDateAndTime (or is omitted), this returns the * calendar date and wall-clock time, as a list: [year, month, * dayOfMonth, dayOfWeek, dayOfYear, hour, minute, second, timer]. * Year is the year AD (for example, 2006); month is the current month, * from 1 (January) to 12 (December); dayOfMonth is the calendar day of * the month, from 1 to 31; dayOfWeek is the day of the week, from 1 * (Sunday) to 7 (Saturday); dayOfYear is the current day of the year, * from 1 (January 1) to 366 (December 31 in a leap year); hour is the * hour on a 24-hour clock, ranging from 0 (midnight) to 23 (11pm); * minute is the minute of the hour, from 0 to 59; second is the second * of the minute, from 0 to 59; and timer is the number of seconds * elapsed since the "Epoch," defined as midnight, January 1, 1970, * midnight UTC. (This is the Epoch that Unix-like systems use, so it * appears frequently in computer timekeeping systems.) See the Date * class for more comprehensive date/time handling. * * If timeType is GetTimeTicks, this return the number of milliseconds * since an arbitrary starting time. The first call to get this * information sets the starting time, so it will return zero; * subsequent calls will return the amount of time elapsed from that * starting time. Note that because a signed 32-bit integer can only * hold values up to about 2 billion, the maximum elapsed time that * this value can represent is about 24.8 days; so, if your program * runs continuously for more than this, the timer value will roll * around to zero at each 24.8 day multiple. So, it's possible for * this function to return a smaller value than on a previous * invocation, if the two invocations straddle a 24.8-day boundary. */ getTime(timeType?); /* * Match a string to a regular expression pattern. 'pat' can be either * a string giving the regular expression, or can be a RexPattern * object. 'str' is the string to match, and 'index' is the starting * character index (the first character is at index 1) at which to * start matching. Returns the length in characters of the match, or * nil if the string doesn't match the pattern. (Note that a return * value of zero doesn't indicate failure - rather, it indicates a * successful match of the pattern to zero characters. This is * possible for a pattern with a zero-or-more closure, such as 'x*' or * 'x?'.) */ rexMatch(pat, str, index?); /* * Search the given string for the given regular expression pattern. * 'pat' is a string giving the regular expression to find, or a * RexPattern object. 'str' is the string to search, and 'index' is * the optional starting index (the first character is at index 1; * negative indices are from the end of the string, so -1 is the last * character, -2 is the second to last, and so on). If a match to the * pattern isn't found, returns nil. If a match is found, the return * value is a list: [index, length, string], where index is the * starting character index of the match, length is the length in * characters of the match, and string is the text of the match. */ rexSearch(pat, str, index?); /* * Get the given regular expression group. This can be called after a * successful rexMatch() or rexSearch() call to retrieve information on * the substring that matched the given "group" within the regular * expression. A group is a parenthesized sub-pattern within the * regular expression; groups are numbered left to right by the open * parenthesis, starting at group 1. If there is no such group in the * last regular expression searched or matched, or the group wasn't * part of the match (for example, because it was part of an * alternation that wasn't matched), the return value is nil. If the * group is valid and was part of the match, the return value is a * list: [index, length, string], where index is the character index * within the matched or searched string of the start of the group * match, length is the character length of the group match, and string * is the text of the group match. */ rexGroup(groupNum); /* * Search for the given regular expression pattern (which can be given * as a regular expression string or as a RexPattern object) within the * given string, and replace one or more occurrences of the pattern * with the given replacement text. * * The search pattern can also be given as a *list* of search patterns. * In this case, we'll search for each of the patterns and replace each * one with the corresponding replacement text. If the replacement is * itself given a list in this case, each element of the pattern list * is replaced by the corresponding element of the replacement list. * If there are more patterns than replacements, the extra patterns are * replaced by empty strings; any extra replacements are simply * ignored. If the replacement is a single value rather than a list, * each pattern is replaced by that single replacement value. * * 'flags' is a combination of the ReplaceXxx bit flags, using '|'. If * the flags include ReplaceAll, all occurrences of the pattern are * replaced; otherwise only the first occurrence is replaced. * * ReplaceOnce and ReplaceAll are mutually exclusive; they mean, * respectively, that only the first occurrence of the match should be * replaced, or that every occurrence should be replaced. ReplaceOnce * and ReplaceAll are ignored if a 'limit' value is specified (this is * true even if 'limit' is nil, which means that all occurrences are * replaced). * * If ReplaceIgnoreCase is included, the capitalization of the match * pattern is ignored, so letters in the pattern match both their * upper- and lower-case equivalents. Otherwise the case will be * matched exactly. If ReplaceFollowCase AND ReplaceIgnoreCase are * included, lower-case letters in the replacement text are capitalized * as needed to follow the capitalization pattern of the actual text * matched: if all the letters in the match are lower-case, the * replacement is lower case; if all are upper-case, the replacement is * changed to all upper-case; if there's a mix of cases in the match, * the first letter of the replacement is capitalized and the rest are * left in lower-case. * * The ReplaceSerial flag controls how the search proceeds when * multiple patterns are specified. By default, we search for each one * of the patterns, and replace the leftmost match. If ReplaceOnce is * specified, we're done; otherwise we continue by searching again for * all of the patterns, this time in the remainder of the string (after * that first replacement), and again we replace the leftmost match. * This proceeds until we can't find any more matches for any of the * patterns. If ReplaceSerial is included in the flags, we start by * searching only for the first pattern, replacing one or all * occurrences depending on the ReplaceOnce or ReplaceAll flag. Next, * if ReplaceAll is specified OR we didn't find any matches for the * first pattern, we start over with the result and search for the * second pattern, replacing one or all occurrences of it. We repeat * this for each pattern. * * If the flags are omitted entirely, the default is ReplaceAll (which * means replace all occurrences, exact case matches only, parallel * searching). * * 'index', if provided, is the starting character index of the search; * instances of the pattern before this index will be ignored. Returns * the result string with all of the desired replacements. When an * instance of the pattern is found and then replaced, the replacement * string is not rescanned for further occurrences of the text, so * there's no danger of infinite recursion; instead, scanning proceeds * from the next character after the replacement text. * * 'limit', if specified, is an integer indicating the maximum number * of matches to replace, or nil to replace all matches. If the limit * is reached before all matches have been replaced, no further * replacements are performed. If this parameter is specified, it * overrides any ReplaceOnce or ReplaceAll flag. * * The replacement text can use "%n" sequences to substitute group * matches from the input into the output. %1 is replaced by the match * to the first group, %2 the second, and so on. %* is replaced by the * entire matched input. (Because of the special meaning of "%", you * must use "%%" to include a percent sign in the replacement text.) */ rexReplace(pat, str, replacement, flags?, index?, limit?); /* * Create an UNDO savepoint. This adds a marker to the VM's internal * UNDO log, establishing a point in time for a future UNDO operation. */ savepoint(); /* * UNDO to the most recent savepoint. This uses the VM's internal UNDO * log to undo all changes to persistent objects, up to the most recent * savepoint. Returns true if the operation succeeded, nil if not. A * nil return means that there's no further UNDO information recorded, * which could be because the program has already undone everything * back to the start of the session, or because the UNDO log was * truncated due to memory size such that no savepoints are recorded. * (The system automatically limits the UNDO log's total memory * consumption, according to local system parameters. This function * requires at least one savepoint to be present, because otherwise it * could create an inconsistent state.) */ undo(); /* * Save the current system state into the given file. This uses the * VM's internal state-save mechanism to store the current state of all * persistent objects in the given file. Any existing file is * overwritten. * * 'metatab' is an optional LookupTable containing string key/value * pairs to be saved with the file as descriptive metadata. The * interpreter and other tools can display this information to the user * when browsing a collection of saved game files, to help the user * remember the details of each saved position. It's up to the game to * determine what to include; the list can include any information * relevant to the game that would be helpful when reviewing saved * position files, such as the room name, score, turn count, chapter * name, etc. */ saveGame(filename, metatab?); /* * Restore a previously saved state file. This loads the states of all * persistent objects stored in the given file. The file must have * been saved by the current version of the current running program; if * not, an exception is thrown. */ restoreGame(filename); /* * Restart the program from the beginning. This resets all persistent * objects to their initial state, as they were when the program was * first started. */ restartGame(); /* * Get the maximum of the given arguments. The values must be * comparable with the ordinary "<" and ">" operators. Note that * because this is an ordinary function call, all of the arguments are * evaluated (which means any side effects of these evaluations will be * triggered). */ max(val1, ...); /* * Get the minimum of the given arguments. The values must be * comparable with the ordinary "<" and ">" operators. Note that * because this is an ordinary function call, all of the arguments are * evaluated (which means any side effects of these evaluations will be * triggered). */ min(val1, ...); /* * Create a string by repeating the given value the given number of * times. If the repeat count isn't specified, the default is 1; a * repeat count less than zero throws an error. 'val' can be a string, * in which case the string is simply repeated the given number of * times; an integer, in which case the given Unicode character is * repeated; or a list of integers, in which case the given Unicode * characters are repeated, in the order of the list. The list format * can be used to create a string from a list of Unicode characters * that you've been manipulating as a character array, which is * sometimes a more convenient or efficient way to do certain types of * string handling than using the actual string type. */ makeString(val, repeatCount?); /* * Get a description of the parameters to the given function. 'func' * is a function pointer. This function returns a list: [minArgs, * optionalArgs, isVarargs], where minArgs is the minimum number of * arguments required by the function, optionalArgs is the additional * number of arguments that can be optionally provided to the function, * and isVarargs is true if the function takes any number of additional * ("varying") arguments, nil if not. */ getFuncParams(func); /* * Convert the given value to a number. This is similar to * toInteger(), but can parse strings containing floating point numbers * and whole numbers too large for ordinary integers. * * If 'val' is an integer or BigNumber value, the return value is * simply 'val'. * * If 'val' is a string, the function parses the string's contents as a * number in the given 'radix', which can be any integer from 2 to 36. * If 'radix' is omitted, the default is 10 for decimal. If the radix * is decimal, and the number contains a decimal point (a period, '.') * or an exponent (which consists of the letter 'e' or 'E', an optional * '+' or '-' sign, and one or more digits), the value is parsed as a * floating point number, and a BigNumber value is returned. For any * other radix, decimal points and exponents are considered non-number * characters. For an integral value, the result will be an integer if * the number is within the range that fits in an integer, otherwise * the result is a BigNumber. The routine will simply stop parsing at * the first non-number character it encounters, so no error will occur * if the string contains text following the number. If the text * doesn't contain any number characters at all, the result is zero. * * If val is true or the string 'true', return 1; if nil or the string * 'nil', returns 0. Leading and trailing spaces are ignored in the * string versions of these values. */ toNumber(val, radix?); /* * Format values into a string. This is similar to the traditional C * language "printf" family of functions: it takes a "format string" * containing a mix of plain text and substitution parameters, and a * set of values to plug in to the substitution parameters, and returns * a new string containing the formatted result. * * 'format' is the format string. Most characters of the format string * are simply copied verbatim to the result. However, each '%' in the * format string begins a substitution parameter; the '%' is followed * by one or more optional qualifiers, then by a type code letter. The * corresponding value from the argument list is formatted into a * string according to the type code, and then replaces the entire '%' * sequence in the result string. By default, the first '%' parameter * corresponds to the first additional argument after 'format', the * second '%' corresponds to the second additional argument, and so on. * You can override the default argument position of a '%' using the * '$' qualifier - see below. * * The arguments following 'format' are the values to be substituted * for the '%' parameters in the format string. * * The return value is a string containing the formatted result. * * See the System Manual for the list of '%' codes. */ sprintf(format, ...); /* * Create a list by repeating the given value the given number of * times. If the repeat count isn't specified, the default is 1; a * repeat count less than zero throws an error. 'val' can be any * value; it's simply repeated in each element of the list. */ makeList(val, repeatCount?); /* * Get the absolute value of a number. The argument can be an integer * or a BigNumber; the return value is the absolute value of the * argument, and has the same type as the argument. (The absolute * value of a positive number X (or zero) is X; the absolute value of a * negative number X is -X.) */ abs(num); /* * Get the sign of a number. The argument can be an integer or a * BigNumber. The return value is an integer: 1 if the argument is * positive, 0 if the argument is zero, -1 if the argument is negative. */ sgn(num); /* * Concatenate the arguments together into a single string. The * arguments can be strings or any types that can be automatically * converted to string for the regular "+" operator; non-strings are * first converted to strings using the same rules that "+" uses when * combining a string with a non-string. If there are no arguments, * the result is an empty string. * * This function is essentially the same as concatenating a series of * values with the "+" operator, but it's more efficient with three or * more values, since the "+" operator has to be applied successively * in pairs; that creates and copies an extra intermediate result * string at each step. This function only creates one result string * and only has to copy each input string once. */ concat(...); /* * Search backwards in the given string for the given regular * expression pattern. 'pat' is a string giving the regular expression * to find, or a RexPattern object. 'str' is the string to search, and * 'index' is the optional starting index (the first character is at * index 1; negative indices are from the end of the string, so -1 is * the last character, -2 is the second to last, and so on; 0 means the * position just after the last character of the string). If 'index' * is omitted, the default is to search the entire string from the end, * which is equivalent to passing 0 or str.length()+1 for 'index'. * * If a match is found, the return value is a list: [index, length, * string], where index is the starting character index of the match, * length is the length in characters of the match, and string is the * text of the match. * * This does the same work as rexSearch(), but searches the string * backwards, from the end to the start. The match must end before the * starting index, which allows for repeated searches: simply pass the * match index from the previous search as the 'index' value for the * next search to find the next earlier match that doesn't overlap the * previous match. * * The meanings of the and flags for a reverse * search are essentially the mirror image of their meanings in a * regular forward search. This is easiest to understand by thinking * about the flags in the abstract. means that the * winning match is the one whose "near" endpoint is closest to the * starting index; means that the winner is the match whose * "far" endpoint is closest to the starting index. The near endpoint * in a forward search is the start of the match, whereas it's the end * of the match in a reverse search. Similarly, the far endpoint is * the end of the match in a forward search and the start of the match * in a reverse search. So in a reverse search, means * that the winner is the match whose ending index is highest, and * means that the winner is the one whose starting index is * highest. */ rexSearchLast(pat, str, index?); } /* * flags for firstObj() and nextObj() */ #define ObjInstances 0x0001 #define ObjClasses 0x0002 #define ObjAll (ObjInstances | ObjClasses) /* * rexReplace() flags */ #define ReplaceAll 0x0001 #define ReplaceIgnoreCase 0x0002 #define ReplaceFollowCase 0x0004 #define ReplaceSerial 0x0008 #define ReplaceOnce 0x0010 /* * getTime() flags */ #define GetTimeDateAndTime 1 #define GetTimeTicks 2 /* * Random number generator IDs for randomize(). */ /* * * RNG_ISAAC - ISAAC is the default generator. It's designed for both * cryptographic application and more mainstream uses. Crypto applications * generally have more stringent requirements for an RNG than ordinary * applications. ISAAC does well with the usual statistical tests for RNGs * and is reasonably fast. * * ISAAC's preferred format for a fixed seed is a string value. */ #define RNG_ISAAC 1 /* * RNG_LCG - LCG stands for Linear Congruential Generator, which generates * numbers using a simple linear formula. This is the old standby of * computer RNGs; it's the sort that comes standard with C compilers. * These generators have been extensively studied and have reasonably good * statistical properties and a number of known weaknesses. The TADS LCG * uses the method described in Knuth, The Art of Computer Programming, * volume 2, p170. * * The LCG's preferred format for a fixed seed is an integer value. */ #define RNG_LCG 2 /* * RNG_MT19937 - Mersenne Twister MT19937 algorithm. This is a widely used * RNG algorithm that's become especially popular for scientific * simulations. It's relatively new, dating from 1997, and was designed to * remedy most of the known shortcomings of linear congruential generators * and other earlier RNGs. It's fast and does well on standard statistical * tests. * * MT's preferred format for a fixed seed is a string value. */ #define RNG_MT19937 3