Difference between revisions of "Iter()"
Latest revision as of 22:06, 13 July 2006
The name of the function iter() appropriately comes from the word iterate as iter() iterates over an input list to form an output list. The input and output delimiters control how the input list is broken down into items which are then fed into eval resulting in other items which are then formed into the output list and returned.
That is, the string, eval, is evaluated once for each item in list replacing the special symbol, ##, with the corresponding item from the input list and the symbol #@ with the position within the list being iterated (starting with 1).
All servers support single-character delimiters and the use of %r as an output delimiter. All servers support some notation for indicating that output items should not be delimited from each other. See below for details.
By default, input and output delimiters are both spaces.
- > say iter(This is a test,strlen(##))
- You say "4 2 1 4"
- > say iter(lnum(10),mul(mul(##,##),10))
- You say "0 10 40 90 160 250 360 490 640 810"
- > say iter(lcon(me),[name(##)]..[money(##)])
- You say "test..1 t1..1 radio..1 The Wizard's Pointy Hat..1"
- > say iter(Was it a cat I saw,[words(##)] #@,s)
- You say "1 1 4 2 1 3"
iter() adds a space between items by default. The way around this is to make use of the null output delimiter, thus:
- > say iter(This is a test,strlen(##),,@@)
- You say "4214"
The default output delimiter across MUSH platforms is a single space, but there are times when it is desireable to have no output delimiter at all. On PennMUSH and RhostMUSH, this is accomplished by using a fourth, empty argument. That is, 'iter(1 2 3,##,,)' evaluates to '123' on PennMUSH and RhostMUSH.
On TinyMUSH and TinyMUX, even with a fourth, empty argument, the default output delimiter continues to be a single space. To achieve no output delimiter at all, the so-called NULL delimiter, @@, notation is used. That is, 'iter(1 2 3,##,,@@)' evalutes to '123' on TinyMUSH and TinyMUX.
On PennMUSH, RhostMUSH, and TinyMUX, eval is evaluated after ## and #@ are substituted. This behavior opens a softcode security hole if the input list contains unvalidated data from a different security context. For this reason, itext() is preferred over ##, and inum() is preferred over #@ whenever the input list contains unvalidated data from a different security context. It is still perfectly reasonable to use ## and #@ when the input list contains only data originating from the same security context as the iter() call itself.
A second issue with the above behavior is that iter() cannot be nested in a useful way. The substitution is made once by the outer-most iter(). That is, the result of 'iter(1 2 3,iter(A B C,##))' is '1 1 1 2 2 2 3 3 3' on PennMUSH, RhostMUSH, and TinyMUX.
On TinyMUSH, ## and #@ are treated as tokens by the parser. That is, the result of 'iter(1 2 3,iter(A B C,##))' is 'A B C A B C A B C'. As a token, the value is controlled by the inner-most iter(). In this approach, there is no second evaluation of items in the input list, and therefore, there is no security vunerability from parsing unvalidated data from a different security context.
Notice that in both cases, ## can only refer to the value of items at exactly one level of nesting.
Even using itext(), inum(), and ilev() has problems. PennMUSH, RhostMUSH, and TinyMUX support nested iter() calls and transform 'iter(1 2 3,iter(A B C,itext(0)[itext(1)]))' into 'A1 B1 C1 A2 B2 C2 A3 B3 C3', but TinyMUSH transforms 'iter(1 2 3,iter(A B C,itext(0)[itext(1)]))' into '1A 1B 1C 2A 2B 2C 3A 3B 3C'. That is, TinyMUSH treats the nesting level opposite from PennMUSH, RhostMUSH, and TinyMUX.
The itext(), inum(), and ilev() functions support full access to items at all nesting levels from any nesting level and are safe to use with unvalidated data from a different security context. In PennMUSH, itext() with levels 0-9 can be abbreviated as %i<level>, e.g. %i0 is itext(0).
Here are some edge cases that explore some of the quirky behaviors:
- &foo me=##-##-##
- think iter(1 2 3,u(foo))
For all of these reasons, and also because at some point PennMUSH, RhostMUSH, and TinyMUX could potentially change to the TinyMUSH behavior, the use of itext(), inum(), and ilev() is recommend in cases where a specific behavior is required.
TinyMUSH 3.1 and TinyMUX 2.4 support multi-character input and output delimiters. That is, 'iter(1--2--3,##,--,==)' produces '1==2==3'. PennMUSH and RhostMUSH support single-character input delimiters, but multi-character output delimiters. That is, 'iter(1-2-3,##,-,==)' produces '1==2==3'.
For servers that support multi-characters delimiters, you can use %r as part of an input delimiter.