Curl/Print version


Curl

The current, editable version of this book is available in Wikibooks, the open-content textbooks collection, at
https://en.wikibooks.org/wiki/Curl

Permission is granted to copy, distribute, and/or modify this document under the terms of the Creative Commons Attribution-ShareAlike 3.0 License.

Example 1

|| ===== begin of program ========
{curl 3.0, 4.0, 5.0, 6.0 applet}
Hello World!
|| ======end of program ========

Explanation

Curl commands appear between {} curly braces - hence the name "Curl".

In this example the first line of the code starts with a comment, the two vertical lines. This is similar to the REMark or // of other languages and is used for documentation.

{curl 3.0, 4.0, 5.0, 6.0 applet}

The second line is the 'herald ' - it declares the language and compatible Curl API version numbers and is similar to the <HTML> header in web pages. It is required. When multiple API version numbers are listed, that means that the applet is intended to be compatible with running in any of those versions of the Runtime Environment (RTE). A user can have more than one version of the RTE installed at the same time, but the highest version installed is the plug-in which will control the interactions with the browser, invoking lower numbered versions of the RTE if needed.

The remaining lines are the applet itself.

Hello World!

|| ======end of program ========

which displays the familiar Hello World!


Example 2

{curl 5.0, 6.0 applet}

|| an example in the declarative style

{Table 
   {row-prototype "Name", "Description", "Cost"},
   {row-prototype "Apple", "A red fruit", "25"},
   {row-prototype "Banana", "A yellow fruit", "25"},
   {row-prototype "Orange", "A reddish-yellow fruit", "50"}
}

|*  Another way to comment 

This is HTML to do the same thing 


 <HTML>
 <BODY>
 <TABLE> 
 <tr><td>Name</td><td>Description</td><td>Cost</td></tr>
 <tr><td>Apple</td><td>A red Fruit</td><td>25</td></tr>
 <tr><td>Banana</td><td>A yellow fruit</td><td>25</td></tr>
 <tr><td>Orange</td><td>A reddish-yellow fruit</td><td>50</td>< /tr>  
 </TABLE>
 </BODY>
 </HTML>
 *|
 

This displays a table just like the declarative HTML inside the Comment.

Lines 1 - 4 are standard.

Line 5 declares a new table.

Lines 6 - 9 put the values into four rows

Line 10 ends the table.


Example 3

{curl 5.0, 6.0 applet}

|| A procedural example

{value
    let my-table:Table = {Table}

    {my-table.add {row-prototype "Number", "Square", "Cube"}}
   
    {for i:int = 1 to 25 do
        let square:int = i*i
        let cube:int = square*i
        {my-table.add {row-prototype i, square, cube}}
    }

    my-table
}

The above example shows some simple procedural code to create a table with the numbers 1 - 25 with Square and Cube Values. Lines 1-3 are as described above.

The 4th line starts a Value Block - this is a mechanism to hide some level of code within a Scope and to Return a Value - in this case to display in the web page. (Curl also has a do block that does not return anything)

Line 5 loads the row that holds the header information into the table.

Line 7 defines a new variable - my-table, of type Table and assigns it an initial value, the {Table} part of the line creates a new instance of Table. Curl does support an any type but its use is slower as the system has to make runtime checks on the type.

Line 9 creates a for iterator with a locally scoped variable i of type integer. Line 10 defines a local variable square and line 11 does the same for cube.

line 12 adds a new row to the table with the values of i, square and cube.

Line 13 ends the for construct.

Line 15 has the name of my-table so the value of my-table will be used as the result of the Value block.

Line 16 ends the value block.


Example 4

{curl 5.0, 6.0 applet}
|| Simple OO example - I know simple OO is never sufficient
|| Lets sub-class an ellipse and define a Circle class (width=height=diameter)
{define-class CircleGraphic {inherits EllipseGraphic}
  field diameter:Distance 
  {constructor {default diameter:Distance = 1cm, ...}
    set self.diameter = diameter
    {construct-super ..., width=diameter, height=diameter}
  }
}

|| Declarative is sooo easy to display stuff lets combine them here
{HBox
    {CircleGraphic diameter=2cm},
    {CircleGraphic diameter=3cm, fill-color="red"},
    {CircleGraphic diameter=5cm}
}


This Example shows some OO capability along with Declarative layout.

Lines 1-3 are as described above.

Line four starts the definition of a new OO class called Circle that inherits from Ellipse (isa relationship).

Line 5 defines a field for the circle to hold the value of the diameter. Didn't really need it could just reference the width and height that is already stored for the ellipse. Likewise we should keep other programmers from changing the value of Width and Height independent of diameter. That's what I mean by simple OO examples are never enough.

Line 6 declares the constructor for the new class. A Little description on the parameters. the first parameter to Circle is a keyword argument that has a default value. Curl supports positional and keyword parameters. The second parameter is the ellipsis "...", also called 'rest arguments'. This is a construct for passing in an arbitrary number of arguments and you get to parse them. It is very helpful and usually isn't too much work.

Line 7 Saves in the diameter value in the objects field called diameter.

Line 8 calls the constructor for Ellipse but overwrites any mention of width and height with the diameter given.

The rest of the program closes out constructor and class definition then creates a simple display to hold a triple of circles. Note that other information is passed to the ellipse (fill-color) by way of the rest arguments. This is a screen capture of the output:

 


The dynamic nature of Curl can be used to create composite applications. Here comes a simple composite program that includes a chat capability and a web browser. Just save the script below as a file


say "c:\webbrowser.curl" and type the following line into your "Run..." field

"c:\Program Files\Curl Corporation\Surge\4\bin\curl.exe" c:\webbrowser.curl

Requirement is that you have Internet Explorer and Curl 3 installed.

You can also show the address bar, automagically fill in forms etc.


Example 5

{curl 5.0, 6.0 script}
{import * from CURL.GUI.STANDARD}
{import ActiveXObject from CURL.GRAPHICS.ACTIVEX}
{let expl:ActiveXObject= {ActiveXObject ProgId="Shell.Explorer" }}
{let expl2:ActiveXObject= {ActiveXObject ProgId="Shell.Explorer" }}
{{View
    {paragraph
        {ActiveXGraphic
            border-width = 1pt, border-color = "green",
            expl, width = 10cm, height = 5cm}
        {ActiveXGraphic
            border-width = 1pt, border-color = "blue",
            expl2, width = 10cm, height = 5cm}
    }
}.show}
{do {expl.Navigate
"http://km0330.keymachine.de/friedger/curlchat/start-chat.curl"}}
{do {expl2.Navigate "http://www.google.com"}}
{event-loop}


Example 6

Curl is a gentle slope language. Here I will put some code to draw a UPC bar code that shows how you can program it using two techniques. Note that in the code below I have used markup and some text procs too. This is to demonstrate how these things can all be done so seamlessly in Curl.

I have implemented the UPC bar code using two techniques. The first technique uses Rule objects to draw the bars of the bar code. The second technique is more efficient. It uses the rendering APIs to render the bars of the bar code.

|| ===== begin of program ========
{curl 5.0, 6.0 applet}
{curl-file-attributes character-encoding = "windows-latin-1"}

{center {bold font-size = 14pt, Universal Product Code}}

{center 
    {small 
      The documentation on Universal Product Code is taken from
      {link href = {url "http://www.wikipedia.com"}, Wikipedia}
    }
}

The Universal Product Code (UPC) is one of a wide varity of bar code
languages called symbologies.

The UPS code has 12 decimal digits as 

S{bold {underline L}LLLLL}M{bold RRRRR{underline R}}E

where S (start) E (end) are the bit pattern 101, M (middle) is the bit
pattern 01010 and each L (left) and R (Right) are digits, each one
represented by a seven-bit code.This is a total of 95 bits.

The UPC has only numerals, with no letters or other characters.

{italic (L) left code}:
{Table
    columns = 2,
    border-width = 1pt,
    vertical-line-width = 1pt,
    horizontal-line-width = 1pt,
    "0", "3-2-1-1",
    "1", "2-2-2-1",
    "2", "2-1-2-2",
    "3", "1-4-1-1",
    "4", "1-1-3-2",
    "5", "1-2-3-1",
    "6", "1-1-1-4",
    "7", "1-3-1-2",
    "8", "1-2-1-3",
    "9", "3-1-1-2"
}

The (R) right codes are one's complement of the corresponding left codes.

I have implemented this in two ways. The first approach uses a Rule
object to draw the bars of the UPC code and the second approach uses
the renderer calls to draw. The first one is easy to write and will
act as the prototype for the second case which is more efficient.

To represent a code we make a Code class that has the four sequences
of 0's and 1's. This code is shared by both the approaches. If you are
running under 6.0 you can make this class a value class. So instead of
"define-class" use "define-value-class".

{define-class public final Code
  field constant public first:int
  field constant public second:int
  field constant public third:int
  field constant public fourth:int

  {constructor public {default first:int, second:int, third:int, fourth:int}
    set self.first = first
    set self.second = second
    set self.third = third
    set self.fourth = fourth
  }
}

{bold Approach 1.}

In this approach we will use a Rule object to represent the bars.

|| Returns an array of UPC codes from 0 to 9 as defined by the table
|| for L codes.. We will use this same table for the R codes except
|| the bits that are one will be considered off and vice-versa.
{define-proc public {get-codes}:{Array-of Code}
    let constant codes:{Array-of Code} = 
        {{Array-of Code} efficient-size = 12}
    {codes.append {Code 3, 2, 1, 1}}
    {codes.append {Code 2, 2, 2, 1}}
    {codes.append {Code 2, 1, 2, 2}}
    {codes.append {Code 1, 4, 1, 1}}
    {codes.append {Code 1, 1, 3, 2}}
    {codes.append {Code 1, 2, 3, 1}}
    {codes.append {Code 1, 1, 1, 4}}
    {codes.append {Code 1, 3, 1, 2}}
    {codes.append {Code 1, 2, 1, 3}}
    {codes.append {Code 3, 1, 1, 2}}

    {return codes}
}

|| Returns a Graphic that represents the UPC code for the
|| "code-str". The code-str sting must represent a valid UPC code
|| number (All the characters in this string should be between '0' and
|| '9' inclusive of the end points, and the twelfth bit should
|| represent the valid checksum for the previous 11 bits.
|| "strip-width" represents number of pixels each bit of the UPC code
|| should be wide. By default it is 2.
{define-proc public {make-upc-graphic 
                        code-str:String,
                        strip-width:int = 2 }:Graphic 
    {validate-code-str code-str} 
    {assert strip-width > 0}
    
    let constant hbox:HBox = 
        {HBox height = 1cm, vstretch? = true, framelike-stretch? = true}
    
    let constant codes:{Array-of Code} = {get-codes}
    let constant black:FillPattern = FillPattern.black
    let constant white:FillPattern = FillPattern.white
    let constant unit:PixelDistance = (strip-width * 1px)

    || Add start code (101)
    {hbox.add {Rule width = unit, color = black}}
    {hbox.add {Rule width = unit, color = white}}
    {hbox.add {Rule width = unit, color = black}}

    || Add L bits.
    {for i = 0 below 6 do
        let constant code:Code = codes[code-str[i] - '0']
        {hbox.add {Rule width = code.first * unit, color = white}}
        {hbox.add {Rule width = code.second * unit, color = black}}
        {hbox.add {Rule width = code.third * unit, color = white}}
        {hbox.add {Rule width = code.fourth * unit, color = black}}
    }

    || Add middle code (01010)
    {hbox.add {Rule width = unit, color = white}}
    {hbox.add {Rule width = unit, color = black}}
    {hbox.add {Rule width = unit, color = white}}
    {hbox.add {Rule width = unit, color = black}}
    {hbox.add {Rule width = unit, color = white}}

    || Add R bits.
    {for i = 6 below 12 do
        let constant code:Code = codes[code-str[i] - '0']
        {hbox.add {Rule width = code.first, color = black}}
        {hbox.add {Rule width = code.second * unit, color = white}}
        {hbox.add {Rule width = code.third * unit, color = black}}
        {hbox.add {Rule width = code.fourth * unit, color = white}}
    }

    || Add end code (101)
    {hbox.add {Rule width = unit, color = black}}
    {hbox.add {Rule width = unit, color = white}}
    {hbox.add {Rule width = unit, color = black}}

    {return hbox}
}

|| Validate the code-str according to the rules of UPC codes.
{define-proc package {validate-code-str code-str:String}:void
    {assert code-str.size == 12}
    let checksum:int
    let count:int = 0
    {for ch in code-str do
        {inc count}
        {if ch < '0' or ch > '9' then
            {error "Invalid Universal Product Code: " & code-str}
        }
        {if count < 12 then
            {if (count mod 2) == 1 then
                set checksum = checksum + 3 * (ch - '0')
             else
                set checksum = checksum + (ch - '0')
            }
         else
            set checksum = 10 - (checksum mod 10)
            {if checksum != ch - '0' then
            {error "Invalid Checksum in Universal Product Code: " & code-str}}
        }
    }
}

This is the result of calling "make-upc-graphic" proc to make a UPC
bars for the UPC code "036000291452".

{make-upc-graphic "036000291452", strip-width = 2}

{bold Approach 2}

Once you become an advanced Curl programmer, you may want to use the
Renderer directly to draw the UPC code bars instead of adding a
Graphical object to represent them.

We make a UPCGraphic class that is a subclass of Graphic. We override
the {italic get-width-preference} and {italic get-height-preference} to
make the default width of this Graphic a multiple of strip-width times
pixel-size and the default height of 1cm. We also override the {italic
draw} method of this Graphic to draw the UPC code bars.

{define-class public UPCGraphic {inherits Graphic}
  || There are total of 95 strips in a UPC code bar.
  let private number-of-strips:int = 95
  || The UPC codes.
  let private codes:#{Array-of Code}

  || The UPC code that this UPCGraphic represents.
  field constant public code-str:String
  
  || This determines the default width of this Graphic object. The
  || default width is strip-width times the pixel size.
  field constant  public strip-width:int

  || Returns the UPC codes. Note that this is a class proc and it
  || initializes the UPCGraphic.codes class variable.
 {define-proc public {get-codes}:{Array-of Code}
    {return
        {if-non-null codes = UPCGraphic.codes then
            codes
         else
            let constant codes:{Array-of Code} = {{Array-of Code}}
            {codes.append {Code 3, 2, 1, 1}}
            {codes.append {Code 2, 2, 2, 1}}
            {codes.append {Code 2, 1, 2, 2}}
            {codes.append {Code 1, 4, 1, 1}}
            {codes.append {Code 1, 1, 3, 2}}
            {codes.append {Code 1, 2, 3, 1}}
            {codes.append {Code 1, 1, 1, 4}}
            {codes.append {Code 1, 3, 1, 2}}
            {codes.append {Code 1, 2, 1, 3}}
            {codes.append {Code 3, 1, 1, 2}}
            set UPCGraphic.codes = codes
            codes
        }
    }
  }
  
  || Class proc to validate the UPC code string.
  {define-proc private {validate-code-str code-str:String}:void
    {assert code-str.size == 12}
    let checksum:int
    let count:int = 0
    {for ch in code-str do
        {inc count}
        {if ch < '0' or ch > '9' then
            {error "Invalid Universal Product Code: " & code-str}
        }
        {if count < 12 then
            {if (count mod 2) == 1 then
                set checksum = checksum + 3 * (ch - '0')
             else
                set checksum = checksum + (ch - '0')
            }
         else
            set checksum = 10 - (checksum mod 10)
            {if checksum != ch - '0' then
            {error "Invalid Checksum in Universal Product Code: " & code-str}}
        }
    }
  }

  || The constructor for the UPCGraphic object. You must pass a
  || code-str that represents a valid UPC code.
  {constructor public {default
                          code-str:String,
                          strip-width:int = 2,
                          ...
                      }
    {UPCGraphic.validate-code-str code-str}
    {assert strip-width > 0}
    set self.code-str = code-str
    set self.strip-width = strip-width
    
    {construct-super ...}
  }

  {method public open {get-width-preference lc:LayoutContext}:Dimension
    let constant psize:Distance = lc.layout-display-context.pixel-size
    {return psize * self.strip-width * UPCGraphic.number-of-strips}
  }

  {method public open {get-height-preference lc:LayoutContext}:Dimension
    {return 1cm}
  }

  {method public open {constrain-height
                          lc:LayoutContext,
                          ascent:Distance,
                          descent:Distance
                      }:Dimension
    let constant psize:Distance = lc.layout-display-context.pixel-size
    {return psize * self.strip-width * UPCGraphic.number-of-strips}
  }

  {method public open {constrain-width
                          lc:LayoutContext,
                          lextent:Distance,
                          rextent:Distance
                      }:Dimension
    {return 1cm}
  }

  {method public open {draw renderer2d:Renderer2d}:void
    {super.draw renderer2d}
    
    let constant psize:Distance = renderer2d.pixel-size
    let constant bounds:GRect = {self.layout.get-bounds}
    
    let x:Distance = -bounds.lextent
    let constant y:Distance = -bounds.ascent
    let constant height:Distance = bounds.height
    let constant unit-size:Distance = 
        {self.quantize-width bounds.width / UPCGraphic.number-of-strips}
    let constant white:FillPattern = FillPattern.white
    let constant black:FillPattern = FillPattern.black
    let constant codes:{Array-of Code} = {UPCGraphic.get-codes}
    let constant code-str:String = self.code-str

    || Draw Start bits (1, 0, 1)
    {renderer2d.render-rectangle
        x, y, unit-size, height, fill-pattern = black
    }
    set x = x + unit-size
    {renderer2d.render-rectangle
        x, y, unit-size, height, fill-pattern = white
    }
    set x = x + unit-size
    {renderer2d.render-rectangle
        x, y, unit-size, height, fill-pattern = black
    }
    set x = x + unit-size

    {for i = 0 below 6 do
        let constant code:Code = codes[code-str[i] - '0']

        {renderer2d.render-rectangle
            x, y, unit-size * code.first, height, fill-pattern = white
        }
        set x = x + unit-size * code.first
        {renderer2d.render-rectangle
            x, y, unit-size * code.second, height, fill-pattern = black
        }
        set x = x + unit-size * code.second
        {renderer2d.render-rectangle
            x, y, unit-size * code.third, height, fill-pattern = white
        }
        set x = x + unit-size * code.third
        {renderer2d.render-rectangle
            x, y, unit-size * code.fourth, height, fill-pattern = black
        }
        set x = x + unit-size * code.fourth
    }

    || Draw Middle Bits bits (0, 1, 0, 1, 0)
    {renderer2d.render-rectangle
        x, y, unit-size, height, fill-pattern = white
    }
    set x = x + unit-size
    {renderer2d.render-rectangle
        x, y, unit-size, height, fill-pattern = black
    }
    set x = x + unit-size
    {renderer2d.render-rectangle
        x, y, unit-size, height, fill-pattern = white
    }
    set x = x + unit-size
    {renderer2d.render-rectangle
        x, y, unit-size, height, fill-pattern = black
    }
    set x = x + unit-size
    {renderer2d.render-rectangle
        x, y, unit-size, height, fill-pattern = FillPattern.white
    }
    set x = x + unit-size
    {for i = 6 below 12 do
        let constant code:Code = codes[code-str[i] - '0']

        {renderer2d.render-rectangle
            x, y, unit-size * code.first, height, fill-pattern = black
        }
        set x = x + unit-size * code.first
        {renderer2d.render-rectangle
            x, y, unit-size * code.second, height, fill-pattern = white
        }
        set x = x + unit-size * code.second
        {renderer2d.render-rectangle
            x, y, unit-size * code.third, height, fill-pattern = black
        }
        set x = x + unit-size * code.third
        {renderer2d.render-rectangle
            x, y, unit-size * code.fourth, height, fill-pattern = white
        }
        set x = x + unit-size * code.fourth
    }
    || Draw End Bits bits (1, 0, 1)
    {renderer2d.render-rectangle
        x, y, unit-size, height, fill-pattern = black
    }
    set x = x + unit-size
    {renderer2d.render-rectangle
        x, y, unit-size, height, fill-pattern = white
    }
    set x = x + unit-size
    {renderer2d.render-rectangle
        x, y, unit-size, height, fill-pattern = black
    }
  }
}

This is the result of calling UPCGraphic and passing "036000291452".

{UPCGraphic "036000291452"}

 || ======end of program ========


Setting up

Before you can run any Curl application you have to install the Curl Engine. It is available as the Curl Runtime Environment (RTE) which is a browser plug-in, or as the Curl IDE which is a development environment that includes the RTE.

Both are available from Curl Inc..

After downloading just open the installation file. An installation wizard will guide you through the installation.

After the installation just goto any website that features a Curl application.

Calling an applet will start the Curl Engine and the applet will run.

Note, that Curl has a security policy which uses a privilege system. Some applets needs privileges, e.g. applets that are run from your local machine. Privileges are necessary if the applet requires access to your local file system, etc. In order to give privileges you have to enter the location of the application into the Curl Surge Control Panel, under menu item "Privileged Locations".


Version numbers

The version number in applets, scripts and packages specifies the Curl API that has to be supported by the Curl Engine, i.e. by the plug-in. It is possible to have several APIs installed at the same time. Currently, Curl Inc. offers versions 5.0.3, 4.0.5 and 3.0.11 for download.

Within an application the Version number cannot be changed, i.e. each package has to be written for the same API. This eliminates the problems with downwards-compatibility.

However, it is possible to use other version by creating sub-applications, that are applications which run within an application. There is a (limited) possibility to exchange information between the main-applet and sub-applets.


Linux support

Curl supports several versions of Linux now, but if you are a Linux fan, you can, of course, make Curl run on almost any Linux desktop.

Hardware:

Pentium® 166 MHz

Minimum of 64 MB RAM

46 MB hard disk space

Supported browsers:

  • Firefox 2.0, 3.0
  • Konqueror 3.x, 4.x
  • Opera 9.5, 10


The IDE

The VLE (Visual Layout Editor) is adequate. The online help (Curl Documentation Viewer) is an outstanding resource. With the IDE installed the online examples in the help are 'live' output from code that can be edited, restored and saved as an applet. This feature is usually only found in an advanced IDE such as Smalltalk.

The VLE is an interesting place to start: the source code for the VLE is installed as part of the IDE installation - it is written in Curl and constitututes a very large example.

There is a java-type packaging system that encourages modular software. Imported packages are usually a part of compilation (on the fly) and code reuse.

Curl provides an OCC (Occasionally Connected Computing) set of features for applications which can also run when not connected to the Internet: this includes client-side persistent data and local protected storage for each user of a web application.

One of the web GUI challenges is 'stretchy' widgets provided in Curl by using make-elastic. This is a feature required in most RIA applications.


Interviews

Interviews

Please feel free to add your own questions and answers!

Interview with "The Fridge" edit

Are you known as 'the Fridge' because you are a kewl programmer? edit

When last time I had a temperature I wasn't so kewl. I think Fridge is the transcription of the German word "Fritte" (like potato chips) which is my nickname in Germany.

Is Curl evolutionary or revolutionary? edit

This binary question is not so easily answered. Curl is of course evolutionary because there have been other programming languages before. It wouldn't be the MIT if they hadn't learnt from previous mistakes. On the other hand Curl comes with a revolutionary license policy. Don't ask for details the answer might take months.

What is your favourite piece of Curl programming? Hint: try and include curlchat edit

I would say the "Hello World" program, as it nicely shows how markup language is integrated in the object-oriented programming language. There are also some really good applications around, most of them are not available on the net but have a look a www.curlchat.info for example and you will know what I mean.

Can Curl be used for programming mobile phones or PDA's? edit

No, not yet. If the Asian market produces enough revenue there might be a possibility that Curl is ported to these devices.

Why is your baby son a worshipped deity? edit

I don't understand the question.

How does Curl fit in with the Semantic Web? edit

Oh, a technical question. Curl is great in collection information and preparing them in a sensible way. Yes, Curl programs can give meaning to a arbitrary sets of data retrieved from different sources.

What is your connection to alchemy and time travel? edit

Yesterday, I was working with Curl version 4.2 that was released in 1992. But unfortunately, I was already so rich (look at all these gold nuggets on my desk) that I couldn't to see the ingenuity of the release.

Why are you so keen on Curl? edit

Because. Do you really want a personal answer?


External links

External links edit