REBOL/Core 2.5 Changes
First Release: March 2001
Back to REBOL Change Logs
Contents
Command Line Startup (Fixes CGI/shell scripts)
Implied Quit
Corrupt Datatype Failure
Help Native! Fixed
Get on NONE
Set-Browser-Path
DO On Command Line
FIND/Any Bug Fixed.
Molding Empty File Names
Core 2.5.5
Main Purpose
New Core License
Startup Files (user.r and rebol.r)
How Scripts are Started
Command Line Terminator (CR)
Changes to SECURE
MOLD/Flat Refinement
Truncation of Series Index (when Past Tail)
AT on PORTs
Added SIXTH Through TENTH Functions
Lines Longer Than 4 KB in Direct/Lines Mode
DECODE-CGI Handles Duplicate Names
ALTER Fixed
Network Errors in TRY (Net-Error Throw)
Extended FTP Directory Paths
STATS for SYSTEM/STATS
PURL Captured
Core 2.5.3
Credits
MAKE-DIR Rewritten
New Bitset Functions: CLEAR, LENGTH?, EMPTY?
Changes to SKIP Function
ARRAYs Initialized with Block Values
Added PARSE BREAK Word
Fix to OPEN on Network Ports
Fixed Crash on Modified Functions
CHANGE Accepts Any Type Value
Unset Object Variables (on Exit)
Added BUILD-MARKUP Function
Revised BUILD-TAG Function
Revised DECODE-CGI Function
UNPROTECT Fixed
ALTER added to Core
SYSTEM Word Protected
Error Message for Word Context
Fixed Crash on Future Dates
Core 2.5.2
CONSTRUCT Object Creator
LOAD Change (Important)
HELP Expanded
SUFFIX? Function Added
SIGN? Function Added
COMPONENT? Function Added
SEND Function Updated
Miscellaneous Fixes
TYPE? (As used in PARSE)
MOLD/ALL
FTP
Core 2.5.1
Source Code Form for Values of NONE, TRUE, etc.
Less Aggressive Evaluation (Important!)
COMPOSE/ONLY Inserts Blocks
REMOVE-EACH - Easy Series Element Removal
ATTEMPT for Error Handling
EXTRACT Function Updated
SAVE to Memory
SEND Refinements /Subject /Attach
Difference for Date/time
System Port Added
Core 2.5.0
New Sort Function
Terminology
Arguments
Comparators
File Modes
Getting Lists of Modes
Modes Available
Using File Forks
Finding All Forks
Serial Port Access
Specifying a Serial Port
Operation
Objects
Make Object Object
Third Object
Mold and Load Changes
File and Port Changes
Network Protocol Change (APOP, IMAP)
Data Series Changes
Math Related Changes
Command Line Changes
Console
Control
Interpreter
Other Changes
Interpreter Fixes
Networking Fixes
Other Function Fixes
Core 2.5.6
Miscellaneous fixes made during the version 2.5.6 releases of the /SDK, /Command, and /SDK/Command products.
Command Line Startup (Fixes CGI/shell scripts)
REBOL ignores CR characters (13) in script files, but a problem occurred if a CR appeared on the command line that started REBOL. REBOL would display HELP information. This problem has been fixed and solves the problem that may occur when you used an FTP binary transfer of a CGI script to your Linux/Unix web server.
Implied Quit
All REBOL products are now consistent in what they do when a script has finished running, but did not execute a QUIT. They now now force a QUIT at the end of the script. If you want to go to the REBOL console, put a HALT in your script.
Corrupt Datatype Failure
In some situations REBOL would crash at the end of a script with a "corrupt datatype" error. This was caused by optimizations made in 2.5.3 that freed unused internal structures. The problem would only occur when a script caused memory recycling and did not include a QUIT or HALT at its end. This has been fixed.
Help Native! Fixed
Requesting HELP on NATIVE! has been fixed (the native! word has been restored).
Get on NONE
A GET of NONE is now allowed and will return NONE.
print get none
This makes it easier to write code that fetches values from an object when the word within the object may be missing. For example, the code below will no longer cause an error if the word is missing from the object:
value: get in object 'word
This makes code simpler for cases like CGI object form values:
cgi: construct decode-cgi read-cgi name: any [get in cgi 'name "default"]
In the example above, if the cgi/name does not exist, the default string is used. No error will occur if the name is missing from the CGI object.
Set-Browser-Path
The SET-BROWSER-PATH function now accepts REBOL filename format. It will also accept a string that is in local OS file format (when provided as a string! type). You can also set it to NONE.
The SET-BROWSER-PATH function will also return it's prior setting.
If you wish to disable this function (for security reasons), you can set it to NONE or unset the function.
set-browser-path: none unset 'set-browser-path
DO On Command Line
The --do option is processed again on the command line. This allows you to pass expressions to be executed from the shell command line. For example:
rebol --do "probe system/options/args"
Note that --do now happens after the rebol.r and user.r files are evaluated (letting you initialize your own custom functions and values) but before the script on the command line is evaluated.
The --do option can be used to define variables prior to the execution of your script. For example:
rebol make-website.r --do "verbose: true"
would set the VERBOSE variable to TRUE at the start of execution. To set the default value in the script, you might use code such as:
if not value? 'verbose [verbose: false]
FIND/Any Bug Fixed.
A serious error was reported related to using FIND with the /any refinement (wildcards). For some cases FIND/any would return a valid string rather than NONE. For example:
find/any next "abc" "d"
returned "c". This problem has been fixed.
Molding Empty File Names
MOLDing an empty filename resulted in source code that could not be loaded. In rare cases, this might case a SAVE to create a file that LOAD could not handle. Molding an empty file name now outputs the characters %"" to avoid this problem. This fixes the problem in MOLD, SAVE, and PROBE.
Core 2.5.5
Main Purpose
The primary purpose of the Core 2.5.5 release is to bring REBOL/Core into closer compatibility with the new Mac OS X and REBOL/SDK kernels.
New Core License
REBOL/Core licensed has changed to allow personal, educational, or commercial use of the CORE software free of charge.
Note that this license change only applies to REBOL/Core (and will be added to the next release of REBOL/View), but it does not apply to REBOL/SDK, /Command, /IOS or other REBOL commercial products.
Startup Files (user.r and rebol.r)
Beta V2.5.4 did not evaluate the rebol.r and user.r files. V2.5.5 evaluates them again, although using a slightly different method. This should not affect your program. The order is still:
- Check the current directory first.
- Check the system/options/home directory second.
This allows you to have a single standard rebol.r file (and optionally a user.r file) that is shared by all users on multiuser systems.
How Scripts are Started
The method used to start initial scripts has been modified.
This change will have no affect on your programs, but it will produce a better error message on script errors by eliminating the error line that refers to the problem being "Near do-boot". That line was confusing to new users, because do-boot was not part of their script file.
Command Line Terminator (CR)
REBOL no longer shows Usage info if a CR char is passed from a Unix shell on the shell command line.
Although REBOL scripts properly read and load with respect to the CR (ASCII 13) character, some operating systems will pass the CR as a command line argument, causing older versions of REBOL to print its usage help information.
For example, you might see a problem with a CGI shell script starting with:
#!/home/user/rebol -cs REBOL [...]
that was written on a Windows system and transferred to Linux without converting line terminators.
This case has been fixed.
Changes to SECURE
Beta V2.5.4 did not set SECURE prior to running scripts (in other words, it functioned like REBOL/Base).
With V2.5.5 security is being set again, although with a slight change: by default you can now write to a script's target directory. For example, if you run:
REBOL /home/test/script.r
REBOL will startup with WRITE access to /home/test. All other directories will be set to READ only (with WRITE ask).
This change makes it easier for users to write scripts that write and update local data files without the need to provide a -S command line option, but it still protects the rest of your files.
Note that the +S command line option has also been changed. Previously, +S meant SECURE QUIT, which was almost useless because your REBOL would QUIT as soon as it tried to read its rebol.r and user.r files. Now +S means SECURE ASK, so running with:
rebol +s script.r
Will prompt the user for all READ/WRITE operations for files and networking. A safe mode of operation, but less strict than before.
In addition, the --secure options should also work again now:
rebol --secure allow script.r rebol --secure ask script.r
MOLD/Flat Refinement
The /flat refinement allows you to MOLD code and data without line indentation, making the resulting string smaller (for sending over a network, storing as compressed data, encapping, etc.).
For example:
blk: [ name [ first "Bob" last "Smith" ] options [ colors [ red green blue ] ] ] >>print mold blk [ name [ first "Bob" last "Smith" ] options [ colors [ red green blue ] ] ] >> print mold/flat blk [ name [ first "Bob" last "Smith" ] options [ colors [ red green blue ] ] ]
Truncation of Series Index (when Past Tail)
The handling of an "past the tail" series index has been changed.
In prior versions of REBOL, referring to a series past its tail would cause an error:
>> a: "ABC" == "ABC" >> b: next a == "BC" >> clear a == "" >> insert b "X" ** Script Error: Out of range or past end ** Near: insert b "X"
In some situations, this problem could become difficult to detect, because nearly any reference to B would cause the error.
>> tail? b ** Script Error: Out of range or past end ** Near: tail? b
As a result, the "past end" handling has been relaxed. For many functions, the index will now truncate to the current tail of the series:
>> a: "ABC" == "ABC" >> b: next a == "BC" >> clear a == "" >> tail? b == true
AT on PORTs
The AT function (similar to the SKIP function) now works for the Port datatype.
Added SIXTH Through TENTH Functions
Five new ordinal functions have been added:
sixth seventh eighth ninth tenth
The benefit of these function becomes more clear when you consider using them to pick values from a series (instead of using an object field).
name-of: :first age-of: :second date-of: :third ... product-of: :ninth ... if empty? product-of record [print "missing product"]
The line above is much more readable than:
if empty? ninth record [print "missing product"]
Here's a handy utility function for creating such named accessors:
ordain: func [ "Defines ordinal accessors (synonyms)." words [block!] /local ords ][ ords: [first second third fourth fifth sixth seventh eighth ninth tenth] foreach word words [ set word get first ords ords: next ords ] ]
The above example would then be simplified to:
ordain [name-of age-of date-of ... product-of] ... if empty? product-of record [print "missing product"]
Lines Longer Than 4 KB in Direct/Lines Mode
Earlier versions of REBOL did not properly expand their internal line buffers beyond 4 KB for files opened in direct/lines mode. As a result, lines longer than 4 KB (no line terminators for more than 4 KB) would not be read correctly and would cause an end of file. This problem has been fixed in the current release.
DECODE-CGI Handles Duplicate Names
With increased use of REBOL for CGI scripts, we've expanded the DECODE-CGI function to handle duplicate name fields.
For example, checklists used in web forms may return multiple values for a single variable. DECODE-CGI will now make these multivalued returns into blocks:
>> cgi-str: {name=bob&option=view&option=email&} >> decode-cgi cgi-str == [name: "bob" option: ["view" "email"]]
ALTER Fixed
A serious error in the ALTER function (a data set flagging function, see updated docs in The REBOL Dictionary caused it to malfunction. This problem has been fixed.
Network Errors in TRY (Net-Error Throw)
The NET-ERROR function used THROW for errors, rather than just letting the error throw itself. This caused some types of network errors to bypass a higher level catch when using TRY.
This meant that if you used a TRY around sections of your code, certain network errors (such as an SMTP problem) may be thrown past it, which would cause the error to be passed all the way out to user at the console. This was a problem for SDK scripts, and has been fixed.
Extended FTP Directory Paths
When using FTP URLs, there was no easy way to provide a full path from the root directory.
For example, your logon directory may be:
/home/luke/
but you want to refer to:
/var/log/
In the new release, you can use a double slash URL to provide the absolute directory path:
read ftp://user:pass@host//var/log/messages
(Please tell us if you have any problems using this format.)
STATS for SYSTEM/STATS
The STATS function is now directly accessible. You no longer need to use SYSTEM/STATS.
In addition, the STATS function now more accurately computes memory usage.
PURL Captured
The variable PURL used in DECODE-URL is now a local variable rather than a global.
Core 2.5.3
Credits
Thanks go to these contributors for their feedback, suggestions, or solutions:
Andrew Martin "Anton" Cal Dixon Carl Sassenrath Ernie van der Meer Gregg Irwin Ladislav Mecir Maarten Koopmans "Mr. Martin Mr. Saint" Reichart Von Wolfsheild
It is not always possible to get every change into each new release, but if you have found a bug that's causing you problems, please let us know and we'll do our best to fix it. Provide a very short, repeatable example of the problem, and if you have a fix to the problem, send that along as well. (You'll see the fix happen much faster that way.)
MAKE-DIR Rewritten
The MAKE-DIR function has been rewritten and now works correctly. In addition, it has been relaxed to not cause an error when the specified directory exists. Use the EXISTS? function if you need to check that.
New Bitset Functions: CLEAR, LENGTH?, EMPTY?
Three new functions (actions) have been added to bitsets:
The CLEAR function quickly clears all bits to zero.
The LENGTH? function returns the number of bits in the bitset (always multiple of 8).
The EMPTY? function returns TRUE if any bit is set, otherwise it returns FALSE. (Note that EMPTY? is the same function as TAIL?; therefore, TAIL? also returns the same results, but the word has no meaning for bitsets.)
Bitsets are used as high performance logic arrays for character sets and hashes.
Examples:
>> items: make bitset! 40 == make bitset! #{0000000000} >> length? items == 40 >> empty? items == true >> insert items 10 == make bitset! #{0004000000} >> empty? items == false >> clear items == make bitset! #{0000000000} >> empty? items == true >> empty? negate items == false
Changes to SKIP Function
There are three changes to SKIP that you should note:
1. SKIP now handles decimal offsets correctly. Values are truncated down to lower integer value. (Note that decimal offsets should be used with caution because 1.9999999 is not the same as 2.0 when it comes to indexing.)
>> skip "abc" 1.9999999 == "bc" >> skip "abc" 2.0 == "c"
2. SKIP can have a logic offset. It is made consistent with PICK and AT when used with logic offsets.
>> pick [red green] true == red >> skip [red green] true == [red green] >> at [red green] true == [red green] >> pick [red green] false == green >> skip [red green] false == [green] >> at [red green] false == [green]
For logic offsets, SKIP is identical to AT.
3. SKIP on images will offset pixels, not RGBA bytes. This is consistent with AT, PICK, and POKE. If you are currently using skip on images, this change will affect your code.
ARRAYs Initialized with Block Values
If a block value is provided as the initial element value in the ARRAY function, each element should be the block, not the contents of the block.
In addition, if the initial value is a SERIES of any type (e.g. string, block, email, url) it will be deep copied into each array element (that is, the value of each element will be unique, not shared).
As an example:
>> a: array/initial [2 3] [1 2] == [[[1 2] [1 2] [1 2]] [[1 2] [1 2] [1 2]]] >> append a/1/2 3 == [1 2 3] >> a == [[[1 2] [1 2 3] [1 2]] [[1 2] [1 2] [1 2]]]
Added PARSE BREAK Word
Within some types of PARSE loops such as ANY and SOME, it can sometimes be difficult to write rules that terminate the loop. This happens primarily when using general rules that try to capture "all other cases" within the loop. For example, code such as:
parse item [ any [ "word" (print "got word") | copy value [to "abc" | to end] (print value) ] ]
will end up looping forever because the second rule within the ANY will always succeed, and the ANY will never terminate.
To help solve this problem, the BREAK keyword was added to the parse dialect. Its use is simple. When the BREAK word is encountered within a rule block, the block is immediately terminated regardless of the current input pointer. Expressions that follow the BREAK within the same rule block will not be evaluated.
The above example can now be written as:
parse item [ any [ "word" (print "got word") | copy value [to "abc" | to end] (print value) break ] ]
The ANY loop will be terminated after the second rule.
Generally, for ANY rule blocks that need to terminate at the end of the input stream, you can add an END check followed by the BREAK keyword, such as in this example:
parse item [ any [ end break | "word" (print "got word") | copy value [to "abc" | to end] (print value) ] ]
Fix to OPEN on Network Ports
OPEN on network port under some versions of Windows32 would fail due to an incorrect error code returned from WinSock library (as documented by Microsoft). Fixed.
Fixed Crash on Modified Functions
Fixed the crash that happened when modifying a function's value while evaluating its arguments. For example, the code below:
a: func [x] [print x] b: func [] [a: 42] a b
no longer causes a crash.
Note that modifying a function while it is evaluating may produce odd results that may vary between implementation versions and should generally be avoided.
CHANGE Accepts Any Type Value
To be consistent with INSERT, the CHANGE function allows a new value to be any datatype (ANY-TYPE!).
Users should be aware that a missing value argument will result in a CHANGE value of UNSET!, not an error.
For example:
>> a: [10] == [10] >> do [change a] == [] >> probe a [unset] == [unset]
Unset Object Variables (on Exit)
If exit occurs during object evaluation, unassigned variables not copied from parent object are unset. Fixes the "end" bug where the first variable was set to the END! datatype.
>> probe make object! [exit a: b:] == make object! [ a: unset b: unset ]
Added BUILD-MARKUP Function
This function was inspired by the EREBOL concept of Maarten Koopmans and Ernie van der Meer. Essentially, the idea is that REBOL makes a powerful PHP style markup processor for generating web pages and other markup text.
The BUILD-MARKUP function has been added to support this operation, and will become a standard part of every REBOL implementation.
The BUILD-MARKUP function takes markup text (e.g. HTML) that contains tags that begin with "<%" and end with "%>". It evaluates the REBOL code within each tag (as if it were a REBOL block), and replaces the tag with the result. Any REBOL expression can be placed within the tag. As PHP has shown, this is a very useful technique.
For example:
== build-markup "<%1 + 2%>" >> "3" == build-markup "<B><%1 + 2%></B>" >> "<B>3</B>" == build-markup "<%now%>" >> "2-Aug-2002/18:01:46-7:00" == build-markup "<B><%now%></B>" >> "<B>2-Aug-2002/18:01:46-7:00</B>"
Supplying a <%now%> tag to BUILD-MARKUP inserts the current date/time in the output.
Here's a short example that generates a web page from a template and a custom name and email address:
template: {<HTML> <BODY> Hi <%name%>, your email is <i><%email%></i>.<P> </BODY> </HTML> } name: "Bob" email: bob@example.com page: build-markup template
Don't forget the two % characters within the tag. It's a common mistake.
The value that is returned from the tag code is normally "joined" into the output. You can also use FORM or MOLD on the result to get the type of output you require. The example below loads a list of files from the current directory and displays them three different ways:
Input: "<PRE><%load %.%></PRE>" Result: {<PRE>build-markup.rchanges.txt</PRE>} Input: "<PRE><%form load %.%></PRE>" Result: {<PRE>build-markup.r changes.txt</PRE>} Input: "<PRE><%mold load %.%></PRE>" Result: {<PRE>[%build-markup.r %changes.txt]</PRE>}
If the evaluation of a tag does not return a result (for example using code such as print "test"), then nothing is output. In this case, the output of PRINT will be sent to the standard output device.
Input: {<NO-TEXT><%print "test"%></NO-TEXT>} test Result: "<NO-TEXT></NO-TEXT>"
The BUILD-TAG function can be used within the tag for converting REBOL values into markup output:
Input: {<%build-tag [font color "red"]%>} Result: {<font color="red">}
Tags can set and use variables in the same way as any REBOL script. For example, the code below loads a list of files from the current directory, saves it in a variable, then prints two file names:
Input: "<PRE><%first files: load %.%></PRE>" Result: {<PRE>build-markup.r</PRE>} Input: "<PRE><%second files%></PRE>" Result: {<PRE>changes.txt</PRE>}
Note that variables used within tags are always global variables.
If an error occurs within a tag, an error message will appear as the tag's result. This allows you to see web page errors from any HTML browser.
Input: "<EXAMPLE><%cause error%></EXAMPLE>" Result: {<EXAMPLE>***ERROR no-value in: cause error</EXAMPLE>}
If you do not want error messages to be output, use the /QUIET refinement. The example above would result in:
Result: "<EXAMPLE></EXAMPLE>"
Revised BUILD-TAG Function
The previous version of BUILD-TAG generated poor results for most input combinations. It has been replaced by a new function that was contributed by Andrew Martin. This function produces better results, but ones that are different from the previous function. If you are currently using BUILD-TAG, you will need to adjust your code.
In: [input "checked" type "radio" name "Favourite" value "cat"] Old: {<input="checked" type="radio" name="Favourite" value="cat">} New: {<input checked type="radio" name="Favourite" value="cat">} In: [html xml:lang "en"] Old: {<html="xml:lang"="en">} New: {<html xml:lang="en">} In: [body text #FF80CC] Old: {<body text="FF80CC">} New: {<body text="#FF80CC">} In: [a href %Test%20File%20Space.txt] Old: {<a href="Test File Space.txt">} New: {<a href="Test%20File%20Space.txt">} In: [/html gibber %Froth.txt] Old: {</html gibber="Froth.txt">} New: "</html>" In: [?xml version "1.0" encoding "UTF-8"] Old: {<?xml version="1.0" encoding="UTF-8">} New: {<?xml version="1.0" encoding="UTF-8"?>} In: [html xmlns http://w3.org/xhtml xml:lang "en" lang "en"] Old: {<html xmlns="http://w3.org/xhtml"="xml:lang"="en" lang="en">} New: {<html xmlns="http://w3.org/xhtml" xml:lang="en" lang="en">} In: [html xmlns http://w3.org/xhtml/ xml:lang "en" lang "en"] Old: {<html xmlns="http://w3.org/xhtml/"="xml:lang"="en" lang="en">} New: {<html xmlns="http://w3.org/xhtml/" xml:lang="en" lang="en">}
Revised DECODE-CGI Function
Several bugs have been fixed in DECODE-CGI. More specifically, the function handles empty attribute assignments. Here are some examples:
Input: "name=val1&name=val2" Decoded: [name: "val1" name: "val2"] Input: "name1=val1&name2&name3=&name4=val3" Decoded: [name1: "val1" name2: "" name3: "" name4: "val3"] Input: "name1=" Decoded: [name1: ""] Input: "name2&" Decoded: [name2: ""] Input: "name3=&" Decoded: [name3: ""] Input: "name4=val" Decoded: [name4: "val"] Input: "name5=val&" Decoded: [name5: "val"]
The new function is based on Andrew Martin's contribution. Thanks!
UNPROTECT Fixed
Attempting to UNPROTECT a block containing any value other than a word could cause a crash. Now non-word values are ignored.
ALTER added to Core
The ALTER function found only in View is general purpose and has been made available in all version of REBOL.
SYSTEM Word Protected
To help prevent an accidental beginner mistake that is difficult to debug, the SYSTEM and REBOL words are now protected. If you need to change them, use UNPROTECT first.
Error Message for Word Context
The error message "word not defined in this context" has been changed to "word has no context" to better indicate that the word has never been defined (more precisely, never been bound) in the context of an object, function, or global environment.
Fixed Crash on Future Dates
Prevents startup crash caused by error in Microsoft Windows time functions when running with system date set to greater than 2036.
Core 2.5.2
CONSTRUCT Object Creator
We've added a "light-evaluation" object creator to provide a higher level of security for imported data objects. The function is called CONSTRUCT and it makes new objects, but without a normal evaluation of the object's specification (as is done in the MAKE and CONTEXT functions).
When you CONSTRUCT an object, only literal types are accepted. Functional evaluation is not performed. This allows your code to directly import objects (such as those sent from unsafe external sources such as email, cgi, etc.) without concern that they may include "hidden" side effects using executable code.
CONSTRUCT is used in the same way as the CONTEXT function:
obj: construct [ name: "Fred" age: 27 city: "Ukiah" ]
but, no evaluation takes place. That means object specifications like:
obj: construct [ name: uppercase "Fred" age: 20 + 7 time: now ]
do not produce their evaluated results.
The CONSTRUCT function is useful for importing external objects. For example, loading preference settings from a file can done with:
prefs: construct load %prefs.r
Similarly, you can use CONSTRUCT to load a CGI or email response.
To provide a template object that contains default variable values (similar to MAKE), use the /WITH refinement. The example below would use an existing object called standard-prefs as the template.
prefs: construct/with load %prefs.r standard-prefs
The CONSTRUCT function will perform evaluation on the words TRUE, FALSE, NONE, ON, and OFF to produce their expected values. Literal words and paths will also be evaluated to produce their respective words and paths. For example:
obj: construct [ a: true b: none c: 'word ]
The obj/a value would be logical TRUE, obj/b would be NONE, and obj/c would be WORD.
LOAD Change (Important)
Script header objects are now created by the CONSTRUCT function and they are no longer evaluated.
This change provides a greater level of default security when the LOAD function is used to load REBOL data. The change should affect very few scripts (only those that depend on evaluated header variables -- rare.)
The LOAD function can be used safely without the need to use LOAD/ALL to inspect a script header prior to evaluation.
HELP Expanded
Help can now be used to explore the fields of an object in a user-friendly format. For example, typing this line at the prompt:
help system
will produce this result:
SYSTEM is an object of value: version tuple! 1.0.4.3.1 build date! 1-May-2002/13:31:11-7:00 product word! Link components block! length: 45 words object! [unset! error! datatype! context! native license string! {REBOL End User License Agreement IMPORT options object! [home script path boot args do-arg link- user object! [name email home words] script object! [title header parent path args words] console object! [history keys prompt result escape busy ports object! [input output echo system serial wait-li network object! [host host-address] schemes object! [default Finger Whois Daytime SMTP POP I error object! [throw note syntax script math access co standard object! [script port port-flags email face sound view object! [screen-face focal-face caret highlight- stats native! System statistics. Default is to return locale object! [months days] user-license object! [name email id message]
This works for other types of objects as well as user-created objects. The code below would display the contents of the text-face object created by a View layout:
out: layout [text-face: text "test"] help text-face
Sub-objects can also be viewed. They are specified as paths. For example, to see the options object of the system object:
help system/options
The result would look something like this:
SYSTEM/OPTIONS is an object of value: home file! %/d/rebol/link/ script file! %/d/rebol/link/ranch/utilities/console.r path file! %/d/rebol/link/ranch/ boot file! %/d/rebol/link/rebol-link.exe args none! none do-arg none! none link-url string! "tcp://localhost:4028" server none! none quiet logic! true trace logic! false help logic! false install logic! false boot-flags integer! 2064 binary-base integer! 16 cgi object! [server-software server-name gateway-int
In addition, the search feature in help now provides more information about matches that were made. If you type:
help "to-"
You will now see:
Found these words: caret-to-offset native! Returns the offset position relative to offset-to-caret native! Returns the offset in the face's text co to-binary function! Converts to binary value. to-bitset function! Converts to bitset value. to-block function! Converts to block value. to-char function! Converts to char value. to-date function! Converts to date value. to-decimal function! Converts to decimal value. to-email function! Converts to email value. to-event function! Converts to event value. to-file function! Converts to file value. to-get-word function! Converts to get-word value. to-hash function! Converts to hash value. to-hex native! Converts an integer to a hex issue!. to-idate function! Returns a standard Internet date string. to-image function! Converts to image value. to-integer function! Converts to integer value. to-issue function! Converts to issue value. to-list function! Converts to list value. to-lit-path function! Converts to lit-path value. to-lit-word function! Converts to lit-word value. to-local-file native! Converts a REBOL file path to the local to-logic function! Converts to logic value. to-money function! Converts to money value. to-none function! Converts to none value. to-pair function! Converts to pair value. to-paren function! Converts to paren value. to-path function! Converts to path value. to-rebol-file native! Converts a local system file path to a R to-refinement function! Converts to refinement value. to-set-path function! Converts to set-path value. to-set-word function! Converts to set-word value. to-string function! Converts to string value. to-tag function! Converts to tag value. to-time function! Converts to time value. to-tuple function! Converts to tuple value. to-url function! Converts to url value. to-word function! Converts to word value.
SUFFIX? Function Added
The SUFFIX? function is a helper function that returns the file "extension" portion of a filename or URL. For example:
>> suffix? %into.txt == %.txt >> suffix? http://code.rebol.com/docs.html == %.html >> suffix? %test == none >> suffix? %test.it/file == none
SUFFIX? can be useful when selecting files from a directory. The example below will only select html and htm files:
foreach file load %. [ if find [%.html %.htm] suffix? file [ browse file ] ]
SIGN? Function Added
The SIGN? function returns a positive, zero, or negative integer based on the sign of its argument.
print sign? 1000 print sign? 0 print sign? -1000
The sign is returned as an integer to allow it to be used as a multiplication term within an expression:
new: 2000 * sign val if size > 10 [xy: 10x20 * sign num]
COMPONENT? Function Added
COMPONENT? is a helper function that checks for the existence of a named REBOL component.
if component? 'crypt [print "Encryption available."] if not component? 'sound [print "No sound."]
SEND Function Updated
The SEND function now includes a /SHOW refinement that will show all TO recipients in the header. By default, recipients are not normally shown.
send/show [bob@example.com fred@example.com] message
In addition the FROM field will include the sender's name as well as an email address. The string in system/user/name is used as the from address. For example, if:
system/user/name: "Fred Reboller"
Then when the email is sent, the from field will now appear as:
From: Fred Reboller <fred@example.com>
If system/user/name is NONE or empty, it will not be used.
Finally, some problems in the /ATTACH refinement have been fixed. Attachments of the form:
send/attach user content [[%file.txt "text message"]]
should work properly now. See 2.5.1 notes on SEND for more information about /ATTACH.
Miscellaneous Fixes
TYPE? (As used in PARSE)
Fixed the problem reported in the TYPE? function that caused the datatype error in PARSE. Code of the form below will work properly now:
parse [34] reduce [type? 34] parse [34.5] reduce [type? 34.5]
MOLD/ALL
Fixed the problem with function molding when /ALL refinement is provided.
load mold/all context [test: func [arg] [print arg]]
FTP
Two fixes:
When connecting to a Microsoft IIS based FTP server Rebol did not recognize folders correctly. They were marked as type 'directory but no slash was appended to the file name as done with other types of FTP servers.
In FTP soft-links can now be identified. They can now return an file type of 'LINK.
Thanks: Cal and Reichart at Prolific.com for submitting the above FTP fixes.
Core 2.5.1
Source Code Form for Values of NONE, TRUE, etc.
To better support persistent values between SAVE, MOLD, and LOAD, a new syntactic element has been added to REBOL.
In the past, the source code representation of values like NONE and TRUE required evaluation in order to convert those words into their actual values. For example:
load "NONE"
would return the word NONE, not the value none. This required that your code either evaluate the result (with DO, REDUCE, or TRY) or manually convert the NONE word with code such as:
if value = 'none [value: none]
Thus, if you were storing REBOL data using MOLD or SAVE functions, when you read the data back in, you would need to either evaluate it (e.g. with REDUCE) or add checks for a few specific types of words (as shown above).
To better handle this situation with the literal expression of NONE, TRUE, FALSE, and other values that require evaluation, a new syntactic form has been added to the language:
#[datatype value]
Where datatype indicates the datatype and value provides its value. For simple datatypes such as NONE, TRUE, and FALSE the shorthand form:
#[word]
is also allowed. For example:
#[none]
expresses the value NONE, not the word NONE, even with unevaluated code or data. Similarly,
#[true] #[false]
express the values of TRUE and FALSE within non-evaluated code.
The LOAD, DO, and other source translating functions have been expanded to accept this new syntax. The example below helps show the change:
block: load " none #[none] true #[true] " foreach value block [print type? value] word none word logic
The literal expression of REBOL objects is also allowed by this new format. For example the non-evaluated expression:
#[object! [name: "Fred" skill: #[true]]]
is equivalent evaluating:
make object! [ name: "Fred" skill: true ]
Thus, a persistent (mold/load symmetric) form of objects now becomes available to programmers.
To create or save source code or data using these new datatype expressions, the MOLD and SAVE functions have been given a new refinement called /ALL. This refinement will output the new #[???none] in docs/changes-2-5.txt format for necessary values. For example:
mold/all reduce ["Example" true none time]
word return the string:
["Example" #[true] #[none] 5-May-2002/9:08:04-7:00]
Similarly, using SAVE/ALL would store the above expression to a file.
Less Aggressive Evaluation (Important!)
Variables are no longer aggressively evaluated.
In pervious versions of REBOL, variables that held set-words, parens, paths, and other types of evaluative datatypes would be evaluated on reference. That is no longer the case.
For example, in earlier versions, if you wrote:
a: first [b/c/d] print a
the result would be an evaluation of b/c/d. This evaluation caused problems because it is more common to reference such data, not evaluate it. For instance, you want to be able to write:
data: ["test" A: mold/only (10 + 2.5)] foreach value data [print value]
and smoothly traverse the elements of the data block as simple values. You would not want those values to self evaluate.
This change to evaluation has some deeper implications. For example, it affects any function that specifies literal values within arguments. For example, code such as:
f: func ['word] [print word]
The REBOL design definition of a literal function argument is to accept the argument always as a literal value and NOT evaluate it. However, in the actual implementation it turned out that an evaluation would normally occur when the variable was referenced. (As part of the PRINT in this case.)
For instance, if you passed:
f a/b/c
within the function, the reference to the word would cause the path to be evaluated at that point. Hence, if you referred to the word argument three times, each time it would be evaluated.
This implicit and "aggressive" evaluation, while interesting, was not intuitive and created to hard to find errors with difficult to interpret error messages.
Consider the case where the set-word datatype might be passed as the argument:
f test:
The set word is then evaluated where WORD appeared (in the PRINT line), and it would require an argument. The code would produce an error message that would tell you that the set required an argument. Yet, you would see no set within your code. It would look like an interpreter flaw, when in fact it was doing precisely what you asked.
Since the vast majority of REBOL programs do not rely on this type of evaluation, we've taken it out. This cleans up the semantics of literal arguments, but it also means that where programs depend on passing non-literals and assume that evaluation occurs, they do not. That will break some code, but it is rare. (For example, in the entire source code base of REBOL Technologies, there was only one such case.)
COMPOSE/ONLY Inserts Blocks
The COMPOSE function now has an /ONLY refinement similar to the INSERT/ONLY refinement. When /ONLY is specified, blocks that are inserted are inserted only as blocks, not as the elements of the block (the default). A REDUCE on the block is not required.
For example:
>> block: [1 2 3] >> compose [example (block)] == [example 1 2 3] >> compose [example (reduce [block])] == [example [1 2 3]] >> compose/only [example (block)] == [example [1 2 3]]
REMOVE-EACH - Easy Series Element Removal
The new function REMOVE-EACH works in a similar fashion to FOREACH and makes removing values from strings, blocks, and other series much easier.
Also, in most cases REMOVE-EACH is many times faster than using a WHILE loop and the REMOVE function.
The format of REMOVE-EACH is identical to FOREACH except that it uses the result of the block expression to determine removal. REMOVE-EACH iterates over one or more elements of a series and evaluates a block for each. If the block returns FALSE or NONE, nothing is removed, but if the block returns any other value, the items or items are removed.
remove-each value series [expression]
Similar to FOREACH, REMOVE-EACH can operate on multiple elements from the series (and uses the appropriate skip to get to the next set of elements):
remove-each [val1 val2 val3] series [expression]
Note that in addition to modifying the series, REMOVE-EACH also returns the series as its result.
Here are a number of examples.
To remove the odd numbers from block:
>> blk: [1 22 333 43 58] >> remove-each item blk [odd? item] == [22 58] >> probe blk == [22 58]
To remove all numbers greater than 10 from block:
>> blk: [3 4.5 20 34.5 6 50] >> remove-each item blk [item > 10] == [3 4.5 6] >> probe blk == [3 4.5 6]
To remove all directories from a directory listing:
>> dir: load %. >> remove-each file dir [#"/" = last file] == [%calculator.r %clock.r %console.r %find-file.r...]
To keep only the directories in the listing:
remove-each file load %. [#"/" <> last file]
To remove keep only the .doc files from the listing:
remove-each file load %. [not suffix? ".doc"]
Here is an example of a block that uses multiple values:
blk: [ 1 "use it" 2 "rebol" 3 "great fun" 4 "the amazing bol" ] remove-each [num str] blk [odd? num] remove-each [num str] blk [not find str "bol]
REMOVE-EACH also removes characters from a string:
>> str: "rebol is fun to use" >> remove-each chr str [chr = #"e"] == "rbol is fun to us" >> remove-each chr str [find "uno " chr] == "rblisfts"
ATTEMPT for Error Handling
The ATTEMPT function is a shortcut for the common REBOL idiom:
error? try [block]
The format for ATTEMPT is:
attempt [block]
ATTEMPT is useful in the cases where you either do not care about the error result or you want to make simple types of decisions based on the error.
attempt [make-dir %fred]
ATTEMPT returns the result of the block if an error did not occur. If an error did occur, a NONE is returned.
In the line:
value: attempt [load %data]
the value may be set to NONE if the %data file cannot be loaded (e.g. it's missing or contains an error). This allows you to write conditional code such as:
if not value: attempt [load %data] [alert "Problem"]
Or, even simpler:
value: any [attempt [load %data] 1234]
In this line, if the file cannot be loaded, then the value is set to 1234.
EXTRACT Function Updated
The EXTRACT function now includes an /INDEX refinement to allow you to specify what "column" you want to extract. For example:
data: [ 10 "fred" 1.2 20 "bob" 2.3 30 "ed" 4.5 ] >> probe extract/index data 3 2 == ["fred" "bob" "ed"]
If index is not supplied, then the first column is extracted.
In addition, the extract function has been fixed to properly extract blocks from a block series.
SAVE to Memory
The SAVE function can now write its results into memory. This is useful because the SAVE function contains formatting refinements that are found no where else.
To use SAVE to write to memory, specify a binary value rather than a file name. For example:
bin: make binary! 20000 ; (auto expands if necessary) image: load %fred.gif save/png bin image
Now the BIN binary holds the PNG formatted image. It was not necessary to write it to a file and read it back in.
SEND Refinements /Subject /Attach
The SEND function used for sending email has been extended to easily allow a subject line to be specified with a /SUBJECT refinement. This is a handy shortcut. For example:
letter: read %letter.txt send/subject luke@rebol.com letter "Here it is!"
The above example will send the text of the letter with a subject line as specified. If the /SUBJECT refinement is not given, then the first line of the letter would be used as the subject.
In addition, the SEND function can now include attachment files by providing an /ATTACH refinement. A single file or multiple files can be attached. The specified files can be read from disk or can be provide as a filename and data. The formats are:
send/attach user letter file send/attach user letter [file1 file2 ...] send/attach user letter [[%filename data] ...]
You can also combine the last two above formats.
Example attachments are:
user: luke@rebol.com letter: read %letter.txt send/attach user letter %example.r send/attach user letter [%file1.txt %file2.jpg] send/attach user letter compose/deep [ [%options.txt (mold system/options)] ]
Difference for Date/time
The DIFFERENCE function will now provide the time difference (hours, minutes, seconds) between two date/time values.
>> difference now 1-jan-2000 == 20561:20:26
Normally, when you subtract date/time the result is the number of days, not time:
>> now - 1-jan-2000 == 856
System Port Added
The system port component was added. This component allows direct access to various OS-specific features. For example, the system port can catch Unix and Linux termination signals and perform a controlled shutdown. Under Win32, this port can be used to access win-messages.
More information about the System Port component will be provided as a separate document.
Core 2.5.0
New Sort Function
Several changes and additions have been made to SORT to add functionality, including reverse sorting, hierarchical sorting (sorting on more than one field), sorting of only part of a series, stable sorting (items that are "equal" are not swapped during sorting), and easier specification of sort criteria (without the need for a custom comparator function). The new SORT function is fully backward-compatible.
Terminology
Record | A single logical item in the series to sort. Usually a character if the series to sort is a string, or a value if the series to sort is a block. If the /skip refinement is used then a record consists of multiple, consecutive elements in the series. |
Field | A part of a record. With the /skip refinement and a skip length of n a field is one of n elements in the record. If the /skip refinement is not used and the series to sort is a block which contains sub-blocks, then a field is one item of a sub-block (NOT the complete sub-block). This allows field-wise sorting of blocked records. In all other cases a field is identical to a record (i.e. each record has exactly one field). |
Field offset | An integer specifying the offset of a field within a record. For a record consisting of n fields a field offset can be between 1 and n. |
Arguments
In addition to the series to sort, the new sort action accepts the following refinements. New behavior is marked with New!.
/case | Sort case-sensitive. This only has an effect for fields of type string or character. |
/skip size | Treat series as records of fixed size. size is of type integer. |
/all | Used in combination with the /skip refinement. New! By default only a single field in a record is used for comparison. If the /all refinement is used then all fields in a record are used for comparison. |
/compare comparator | Specify a custom comparator. This can be a field offset (type integer New!), a comparator function, or a comparator block New!. See below. |
/reverse | Sort in reverse. New! |
/part size | Sort only part of a series. (Similar to the use of the /part refinement in copy or change New!). |
Comparators
Sorting is performed by comparing and swapping elements, i.e. comparators define the sort order. The following comparators are supported:
- No comparator (i.e. no /compare refinement). In this case the first field in each record is used for comparison. If the /all refinement is used then all fields in each record are used for comparison. /case and /reverse are observed normally.
- Field offset (integer) New!. Specifies the field to use for comparison. If the /all refinement is used as well then the specified field is the first field to use, and all subsequent fields are used as well. /case and /reverse are observed normally.
- Function. Function called by the sort action to compare two records. The records are passed as arguments, and the function needs to return -1, 0 or 1, if the first record is smaller than, equal to or greather than the second record, respectively. New! For backward compatibility the function may also return true or false, where true indicates that the first record is less than or equal to the second record, and false indicates that the first record is greater than the second record. /case is ignored. /reverse is observed normally, i.e. /reverse inverts the meaning of the comparator function. If the /skip refinement is used then the argument passed to the comparison function only consists of the first field in the record, not the complete record. This is for backward compatibility with the old sort function. In order to pass the complete record, in a block, use the /all refinement.
- Block New!. Comparison dialect specifying the type of comparison in more detail. See below.
Comparison Refinements
The following items can appear in a comparison block:
field offset (integer) | Specifies the offset of the next field to compare. Fields are compared in the order specified. |
reverse (word) | Sets the comparison for all subsequently specified fields to reverse. |
forward (word) | Sets the comparison for all subsequently specified fields to forward (opposite of reverse). |
case (word) | Makes the comparison for all subsequently specified fields case-sensitive. |
no-case (word) | Makes the comparison for all subsequently specified fields case-insensitive (opposite of case). |
to (word) field offset (integer) | Specifies a range of fields to compare, e.g. [???1] in docs/changes-2-5.txt compares fields one to five. |
With comparison blocks the /all, /case and /reverse refinements slightly change their behaviors: /all is equivalent to adding "to max-field" to the end of the comparison block, i.e. when the end of the comparison block is reached comparison continues until the end of the record is reached. /case specifies that the default case mode (until a case or no-case word is reached) is case-sensitive. Otherwise it is case-insensitive. /reverse reverses the resulting list as a whole, and is independent of the reverse/forward words in the comparison block.
Examples
a: [10 "Smith" "Larry" 20 "Smith" "Joe" 80 "Brown" "Harry" 50 "Wood" "Jim"] sort/skip a 3 ; sorts on the first field (number) [10 "Smith" "Larry" 20 "Smith" "Joe" 50 "Wood" "Jim" 80 "Brown" "Harry"] sort/skip/compare a 3 2 ; sorts on the second field (last name) [80 "Brown" "Harry" 10 "Smith" "Larry" 20 "Smith" "Joe" 50 "Wood" "Jim"] sort/skip/compare/all a 3 2 ; sorts on the second field and following fields (last name and first name) [80 "Brown" "Harry" 20 "Smith" "Joe" 10 "Smith" "Larry" 50 "Wood" "Jim"] sort/skip/reverse a 3 ; sorts on the first field (number), in reverse [80 "Brown" "Harry" 50 "Wood" "Jim" 20 "Smith" "Joe" 10 "Smith" "Larry"] sort/skip/compare a 3 [2 reverse 3] ; sorts on the last name forward, and the first name in reverse [80 "Brown" "Harry" 10 "Smith" "Larry" 20 "Smith" "Joe" 50 "Wood" "Jim"]
File Modes
GET-MODES and SET-MODES functions have been added for file and network ports. Two new port actions are introduced:
get-modes | Return current modes for an open port. |
set-modes | Change modes for an open port. |
The get-modes function has the following syntax:
get-modes: native [ {Return mode settings for a port} target [file! url! block! port!] modes [word! block!] ]
The block being passed in consists of words defining which modes should be queried. Each word corresponds to one mode. get-modes returns a block which contains pairs of mode names and current mode settings.
Example:
>> get-modes someport [direct binary] == [direct: true binary: false]
indicating that someport is opened in direct and non-binary (text) mode.
Alternatively a single word can be passed in, in which case get-modes returns the value directly, without putting it into a name-value block.
Example:
>> get-modes someport 'binary == false
As another alternative a name/value-paired block can be passed in, of the same format as the block get-modes returns. In that case the values are ignored.
Example:
>> get-modes someport [direct: none binary: none] == [direct: true binary: false]
The set-modes function has the following syntax:
set-modes: native [ {Change mode settings for a port} target [file! url! block! port!] modes [block!] ]
The block being passed in consists of name-value pairs describing the modes to be changed. A block returned by get-modes can be passed as an argument to set-modes. set-modes returns the port that was passed as an argument.
Example:
>> set-modes someport [direct: false binary: false]
The mode block accepted by set-modes is actually an object-style initialization block and allows multiple names to reference the same value.
Example:
>> set-modes someport [direct: binary: false]
Getting Lists of Modes
get-modes supports a few "special" modes, which do not return mode settings for a specific port, but rather a set of modes that is applicable for a file (or directory, socket etc.). These are "file-modes", "copy-modes", "network-modes" and "port-modes". If any of these modes are specified in a get-modes request then the response contains a block of matching modes which are available on the current filesystem.
>> get-modes somefileordir 'port-modes == [direct binary lines no-wait (...a few more...) ] >> get-modes somefileordir 'file-modes == [file-note creation-date archived script (...a few more...) ] >> get-modes someudpsocket 'network-modes == [broadcast multicast-groups type-of-service]
The above example is for an Amiga. Note that the mode block returned by any of these special requests is identical for all files and directories within a filesystem (and all sockets within a scheme), i.e. it varies per platform and possibly per filesystem and scheme, but not per file or socket. The purpose of this feature is only to provide a mechanism to obtain a list of supported modes, not to obtain the actual mode settings. To obtain the actual mode settings for a port the returned block has to be used in another call to get-modes:
>> get-modes somefileordir get-modes somefileordir 'file-modes == [file-note: "cool graphics" creation-date: 1-Jan-2000 archived: true script: false]
The difference between "file-modes" and "copy-modes" is:
file-modes | Return all modes of the underlying data (typically a file), regardless of how it was opened. |
copy-modes | Same as file-modes, but only return those modes which are safe to copy, i.e. which can (and should) be included in a set-modes call when creating a new file, in order to create an exact clone of an existing file. If a platform provides file properties which are not safe to copy or which necessarily vary on copied files (e.g. Unix inodes) then those modes would show up in the block returned by file-modes, but not by copy-modes. |
Copying all file properties from file1 to file2 can be done with the following call:
>> set-modes file2 get-modes file1 get-modes file1 'copy-modes
Modes Available
File-modes
- status-change-date, modification-date, access-date, backup-date, creation-date: REBOL date. modification-date is available on all platforms. status-change-date is available in Unix. access-date is available in Unix and Windows. creation-date is available in Windows and MacOS. backup-date is available in MacOS. All modes are settable and gettable, except that modification-date and access-date are not settable in Elate.
- owner-name, group-name: REBOL string (user/group name). Available in Unix.
- owner-id, group-id: REBOL integer (user/group id). Available in Unix and AmigaOS (>=V39).
- owner-read, owner-write, owner-delete, owner-execute, group-read, group-write, group-delete, group-execute, world-read, world-write, world-delete, world-execute: REBOL logic. All -read, -write and -execute modes are available in Unix, BeOS, QNX and Elate. owner-read, owner-write, owner-execute and owner-delete are available in AmigaOS. All group- and world- modes are available in AmigaOS >=V39. owner-write is also available in Windows (mapped to the inverse of the Windows "read-only" bit).
- comment: REBOL string (file comment). Available in AmigaOS only.
- script, archived, system, hidden, hold, pure: REBOL logic (additional flags). Script, hold and pure are available in AmigaOS only. Archived is available in AmigaOS and Windows. System and hidden are available in Windows only.
- type, creator: REBOL string. Available in MacOS only.
Platforms which only support a single file date export it via modification-date. Similarly, platforms which do not support multi-user file access modes make the file access modes available via owner-read/write/delete/execute.
Port-modes
- read, write, binary, lines, no-wait, direct: REBOL logic. Binary, lines and no-wait are settable.
Network-modes
- broadcast: REBOL logic. UDP only. Setting this to true allows sending broadcasts from a socket. All platforms except BeOS.
- multicast-groups: REBOL block of blocks. UDP only, describes which multicast groups a socket has joined. Each sub-block consists of two IP addresses (tuples): the multicast group and the IP address of the interface on which the multicast group was joined. Typically available in MacOS, Windows, most Unix platforms, QNX and AmigaOS (Miami/MiamiDx only). Availability is determined at runtime and varies with the OS version and TCP/IP protocol stack version.
- type-of-service: REBOL integer. UDP and TCP. This is the value of the 8-bit "TOS" field in IP headers. Typical values are 0 (default), 2 (minimize cost), 4 (maximize reliability), 8 (maximize throughput) and 16 (minimize latency), but the interpretation of this field is up to the TCP/IP stack and intermediate routers, and not enforced by REBOL. All platforms except BeOS.
- keep-alive: REBOL logic. TCP only. Setting this to true forces TCP to send "keep-alive" packets after a certain period of time (typically 4 hours). All platforms except BeOS.
- receive-buffer-size, send-buffer-size: REBOL integer. UDP and TCP. Size of receive and send buffer within the TCP/IP stack. Default values and allowed ranges vary widely between platforms. Primarily useful for UDP. Increasing this values usually does NOT improve performance. All platforms except BeOS.
- multicast-interface: REBOL string. UDP only. The default interface to use for multicasting. Same platforms as multicast-groups.
- multicast-ttl: REBOL integer. UDP only. The time-to-live value (maximum propagation distance) of multicasts. Same platforms as multicast-groups.
- multicast-loopback: REBOL logic. UDP only. If set to true sent multicasts are looped back to the local socket. Same platforms as multicast-groups.
- no-delay: REBOL logic. TCP only. Disables the Nagle algorithm. Most protocols perform better if this is set to false. It should only be set to true if a protocol is interactive in nature AND relies on precise event timing in combination with queueing (e.g. X11). All platforms except BeOS.
- interfaces: REBOL block of objects. Each object represents one network interface and currently contains the following fields: "name": interface name (on some platforms this is a dummy name). "address": local IP address. "netmask": subnet mask. "broadcast": broadcast address. "remote-address": remote IP address for point-to-point interfaces. "flags": a block of words describing interface properties, currently supported words are "broadcast" (interface supports broadcasting), "multicast" (interface supports multicasting), "loopback" (interface is the loopback interface) and "point-to-point" (interface is a point-to-point interface, as opposed to a multi-drop interface). Some values may be none (e.g. "remote-address" on a multi-drop interface). In Windows all interfaces appears as multi-drop (including PPP), with dummy netmasks. Available in all platforms, except BeOS, Elate, WinCE. Not settable.
Using File Forks
The /custom refinement to read, open and write allows access to different forks of a file (currently useful for MacOS only).
open/custom %myfile [fork "name"] ; Specify which fork to open.
The specified fork name defines which fork to open:
If no fork is specified (no fork specifier in the custom block or none is passed instead of "name"), then for non-Mac platforms the file is opened normally. For Mac the data fork is opened. If the /new refinement is used then the file size is reset to zero bytes. For Mac this means that all forks are reset to zero bytes. (Note: this behavior has changed from Core 2.3. Previously open/new on Macintosh would only reset the size of the data fork, and there was no way to reset the size of the resource fork.)
If a fork is specified by name then that fork is opened. If the /new refinement is used then the size of only that fork is reset to zero bytes. If the fork does not exist (and, for write access, cannot be created) on the current filesystem then an error is thrown.
Non-Mac platforms only have a single fork named "data". Mac platforms have two forks, named "data" and "resource".
Finding All Forks
This is done using the mode mechanism, in a way similar to finding all supported modes.
>> get-modes somefile 'forks == ["data" "resource"]
Example above on Mac. For all other platforms only [???data] in docs/changes-2-5.txt would be returned.
Serial Port Access
This specification describes the creation and operation of serial communication ports within REBOL. Serial ports were supported in version 2.3 but were not documented.
Specifying a Serial Port
Serial ports are created in the same manner as other ports within REBOL. The scheme name for serial ports is "seria". URL's are encoded with the different fields separated by slashes. For example,
port: open serial://port1/9600/8/none/1
The order of values in the serial URL scheme is not significant, as the type of field can be determined by the content. (Note, you can also use a MAKE PORT object rather than a URL to specify a serial port.)
The specification of a serial port may include the device number, the communication speed, the number of data bits, the parity and number of stop bits. The specification information can be specified directly by setting the appropriate fields within the port specification object or by creating a URL which contains the same information. Any field not specified will be given a default value.
The default serial port settings are:
device: port1 speed: 9600 data-bits: 8 parity: none stop-bits: 1
Within a port specification, the various parameters are stored in the following object fields:
host: device speed: speed data-bits: data bits parity: parity stop-bits: stop bits
The portN specification is an indirect reference to the communication device. It refers to the Nth device defined in the System/ports/serial block. This block is initialized by default depending on the system being used and can be modified in user.r to reflect any local requirements.
For example, on Windows the block might be defined as:
System/ports/serial: [ com1 com2 ]
or if COM1 is being used by the mouse, it might just be:
System/ports/serial: [ com2 ]
On unix-style systems, the block might be defined as:
System/ports/serial: [ ttyS0 ttyS1 ]
or if the first device should correspond to COM2:
System/ports/serial: [ ttyS1 ttyS0 ]
Thus, the ports can be specified in a machine indpendent manner while the machine specific definition can be controlled using the serial definition block in System/ports/serial.
Operation
Serial ports are always opened as direct ports in much the same way as console and network ports. They may be opened as either /STRING or /BINARY with the default being /STRING. They are opened by default as asynchronous, but may be made synchronous by using the /WAIT refinement. When operating asynchronously, any attempts to copy data from the port will return NONE if no data is present. When operating synchronously, the copy will block until data is available.
Data can be written to the port using the INSERT native. Data can be read from the port using the PICK, FIRST or COPY natives with the usual ramifications. As usual with direct ports, the REMOVE, CLEAR, CHANGE and FIND functions are not supported.
The UPDATE function can be used to change port parameters. For example, to change the speed after an initial connection has been established, you could just do:
ser-port: open serial://9600 ser-port/speed: 2400 update ser-port
Changing the device number or the System/ports/serial and calling UPDATE will have no effect. Once the port has been opened with a particular device, the device can't be changed.
There are two additional port fields that can't be set with a URL, but can be set in a port specification block or by manually changing them. The RTS-CTS field specifies whether hardware handshaking should be used on the port. The default is ON. To change the default, do:
ser-port/rts-cts: off update ser-port
A timeout value can be specified by modifying the timeout field in the port structure. The timeout value only applies to serial ports that are opened with the /wait refinement. When the timeout expires, a serial port timeout error will be generated. To set the timeout value do:
ser-port/timeout: 10 ; 10 second timeout
Serial ports work properly with the WAIT native.
Objects
- SYSTEM/LOCALE object added. Currently has month and day names.
- Weekdays are separate strings in system/locale/days.
- CONTEXT function added as a shortcut to MAKE object!.
- You can now QUERY an object. QUERY will return a block containing the fields that have been modified in an object since its creation or since it was last passed to QUERY/clear. QUERY will return none if there have not been any changed fields. QUERY/clear will clear the modified state of all the fields in an object.
- Objects now accept LOGIC! values as arguments for to pick (for consistency with blocks).
Make Object Object
You can now make an object out of two other objects, a "template object" and a "spec object". When making a new object out of two other objects, the bindings of words coming only from the "spec object" will be maintained, words shared by both the template object and the spec object will take their values from the spec object. This will cause some differences in behavior because the block spec approach is lexical and the object spec approach is definitional.
Third Object
You can use THIRD on the object to get back a block of set-word value pairs from the object:
z: make object! [a: 99 b: does [a + 1]] t: third z == [a: 99 b: func [][a + 1]]
The block returned from THIRD on an object is like an object spec block, however the set-words are bound to their object. This block is like a snapshot of the object's values at that time. You can also use the returned block to set values in the object:
set first t 199 z/b == 200
Mold and Load Changes
- MOLD/only does not produce the outermost [???none] in docs/changes-2-5.txt in the resulting string.
- Molding a recursive block or object will print [???...] in docs/changes-2-5.txt when on the second instance of the recursive item. So, you can now PRINT MOLD SYSTEM !
- Molding strings greater that 50 characters containing unbalanced "{" characters are now reloadable.
- Added /all refinement to LOAD. LOAD/all of a script does not evaluate the REBOL header. LOAD/all always returns a block.
- LOAD/next/header results in a block with the evaluated header followed by the rest of the script as a string.
- Loading strings with CTRL chars greater than CTRL-Z now allowed.
- Added script HEADER/CONTENT field. When set TRUE, the script's entire source text can be accessed from SYSTEM/SCRIPT/HEADER/CONTENT (when evaluated with DO) or from the header object (when loaded with LOAD/header or LOAD/next/header). This allows your script to access other data that may be part of its script file (e.g. the REBOL archive format, RIP).
LOAD function refinement combinations:
LOAD/Refinement
Eval Header?
Returns
load
yes
returns script (data). If file contains a single value (like 1234), then this returns just that value. If there are multiple values, then it returns a block.
load/next
no
[???first-val] in docs/changes-2-5.txt -- returns a value followed by a string. This refinement lets you parse REBOL files, one value at a time (for operations like pretty printing and colorizing.)
load/next/header
yes
[???header-obj] in docs/changes-2-5.txt -- same as load/next but includes the evaluated header object.
load/header
yes
[???header-obj] in docs/changes-2-5.txt -- returns the script, starting with the REBOL header as the first value.
load/all
no
[???all] in docs/changes-2-5.txt -- returns the script, always as a block, even if it's just a single value (very handy for cases where you always want data as a block, even if it's a single value).
load/next/all
no
[???first-val] in docs/changes-2-5.txt
load/header/all
yes
[???header-obj] in docs/changes-2-5.txt
load/next/header/all
yes
[???header-obj] in docs/changes-2-5.txt
The ALL refinement will be ignored when other refinements are present.
File and Port Changes
- Added asynchronous wait-able DNS for Unix and Windows. For example: open dns:///async, then insert/wait/copy.
- Asynchronous HTTP better supported. You can open/direct/no-wait an HTTP request and use WAIT and COPY to receive the results as they arrive.
- WAIT [???0] in docs/changes-2-5.txt now returns the port if it has data, none otherwise.
- Added WAIT/all refinement, which causes wait to return a block of all ports that have data.
- The /no-wait refinement allows a port to be opened in non-blocking mode. COPY on a non-blocking port returns an empty string unless the end of the port has been reached, in which case it returns none.
- WAIT now supports port handlers (http, tcp etc.) in /direct mode.
- Added AWAKE field in port-specs and root protocol to specify a block or function called when wait is about to wake up. Used to implement background processing.
- WAIT works correctly on /lines ports opened without /with.
- TO-LOCAL-FILE and TO-REBOL-FILE functions can be used to convert to and from the local OS file path formats.
- Added local-port, remote-ip and remote-port fields to port spec for consistent values independent of port creation.
- MAKE-DIR/deep creates all needed directories in a long path.
- CONNECTED? native for most platforms.
- Fixed incorrect port-id assignment on accepted sockets.
- Fixed bug that would prevent UDP listen sockets from responding to packets from different origins.
- SPLIT-PATH was modified to properly split the path and target of a file path.
Network Protocol Change (APOP, IMAP)
- Added APOP
Authentication for pop:// that does not send passwords to the server in clear text. - Added imap:// protocol. URL format and behavior identical to pop://, plus additional URL formats specified in RFC 2192.
- Fixed SEND when /header and no FROM address is given
- Fixed do-send to change email lines with only a single "." to have two periods so those emails will not blow out anymore.
Data Series Changes
- HASH! and LIST! datatypes now offer more complete, consistent, reliable, and faster operation.
- The SELECT, FIND, UNION, INTERSECT, EXCLUDE, DIFFERENCE, and UNIQUE functions accept a /skip refinement to specify data size.
- UNIQUE accepts the /case refinement.
- TO-BINARY of tuples now uses the tuple values instead of forming the tuple.
- JOIN on binary values now joins as binaries, not FORMed strings.
- FIND now works on all types of functions properly.
- FIND/REVERSE works for bitsets.
- Pick on objects and functions with negative number fixed.
- Fixed bug in ENBASE that could cause invalid characters to be inserted into a base-64-encoded string.
- Removed /only refinement from DIFFERENCE (EXCLUDE is equivalent).
- MINIMUM-OF and MAXIMUM-OF series. You can use MINIMUM-OF and MAXIMUM-OF on a single series argument which will return the series offset to the least or greatest contained value respectively. Eg:
minimum-of reduce [pi .099 10 * 100] == [0.099 1000] maximum-of reduce [pi .099 10 * 100] == [1000]
Math Related Changes
- Added CHECKSUM/secure and RANDOM/secure, producing cryptographically secure checksums and random numbers respectively.
- Added CHECKSUM/hash and CHECKSUM/method (same as checksum/secure, but with a selectable algorithm: 'md5 or 'sha1), and checksum/key (calculates a keyed message digest). MD5 added as an alternative checksum algorithm.
- Subtraction of a date! value months bug fixed.
- Time! values can convert to integers and decimals.
- NOW/precise returns greater precision on time. Useful for timing events.
Command Line Changes
- REBOL startup command line now accepts "--" to signal the end of startup switches. Remaining items on the command line are arguments to be passed to the REBOL script. This also allows REBOL to start without a script but with arguments passed.
- When starting from the command line, system/script/args == string of all args, system/options/args == block of separate args. All items following the specification of the script are considered arguments.
- REBOL now deals with arbitrary amount of command line arguments-- no fixed size.
Console
- Console tab completion now completes as much of the defined word or file path as possible.
- Added proper console reinitialization code when REBOL is woken up after Ctrl-Z followed by "fg" (for Unix and shells with job control).
- File name completion in the console is now case-insensitive for operating systems that have case-insensitive file systems (Windows, AmigaOS etc.)
- Screen now gets cleared on first console output, not signon message.
Control
- A BREAK used in the first block of a WHILE will cause a BREAK from the while loop.
- CATCH and THROW work more reliably in more cases.
- FOREACH returns correct value on empty series.
Interpreter
- Binding speed greatly improved for top-level words.
- Indefinite extent fixed for many cases (the USE function).
Other Changes
- HAS function added as a shortcut to define functions with local variables but no arguments.
- Fixed CONFIRM to throw error on bad pick operation.
Interpreter Fixes
The following internal interpreter problems have been fixed.
- Series Expansion: Significant performance and memory problem has been fixed resulting in many times greater speed in some types of uses. This change speeds up MOLD and SAVE by many times.
- Lit-path! comparison works properly
- Time zone bug in date comparison fixed
- Handling of "--" in command line arguments
- Tab expansion of words in console
- Component version numbers added to the boot message
- Increased the global word limit to 8000
- Potential crash during expansion and recycling of hash! values
- Potential crash when recycling open, unreferenced ports
- Port cleanup to close ports in the correct order
Networking Fixes
The following fixes were made to networking:
- DNS
Unix only: fixed lockup when DNS helper process dies unexpectedly. - DNS
Unix only: DNS helper process no longer remains a "zombie" if the main process is killed. - FTP
conflicts with generic proxy setups fixed - FTP
allow more response codes from CWD command in FTP - HTTP
proxy authentication added - HTTP
POST linefeed conversion problem fixed - HTTP
forwarding fixed where host name in header was not updated - POP
will try APOP if port/algorithm is set to 'apop (workaround for bug in some POP servers). - TCP
On Windows only: TCP listen sockets no longer allow multiple listeners on the same port. Workaround for bug in Windows TCP/IP stack regarding SO_REUSEADDR.
Other Function Fixes
Fixes to natives and functions include:
- COMPRESS/DECOMPRESS
series offsets are now allowed - DEBASE
potential crash fixed - DEBASE
series offsets are now allowed - FIND
when using bitset with chars greater than 127 - FIND/MATCH/CASE
fixed - LOAD/MARKUP
potential crash fixed - MAKE
potential crash with make object! object! fixed - MAKE-DIR/DEEP
fixed bug - SET-MODES
fixed file date setting when no time value is provided - SORT
handles hashed blocks now, and potential crashes fixed - UNION, INTERSECT, etc.
series offsets are now allowed on the second argument