Ring/Printable version


Ring

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

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

Lessons/Introduction

Introduction

edit

Welcome to the Ring programming language!

In this chapter we are going to discuss the goals behind the language design and implementation.


Lessons/Motivation

Motivation

edit

In Nov. 2011, I started to think about creating a new version of the Programming Without Coding Technology (PWCT) software from scratch.

I was interested in creating multi-platform edition of the software beside adding support for Web & Mobile development. Most of the PWCT source code was written in VFP and the software comes with a simple scripting language for creating the components called (RPWI). The software contains components that support code generation in programming languages like Harbour, C, Supernova & Python.

What i was looking for is a programming language that can be used to build the development environment, provides multi-platform support, more productivity, better performance, can be used for components scripting & can be used for developing different kinds of applications.

Instead of using a mix of programming languages, I decided to use one programming language for creating the development environment, for components scripting & for creating the applications.

I looked at many programming languages like C, C++, Java, C#, Lua, PHP, Python & Ruby. I avoided using C or C++ directly because i want high-level of productivity more than the level provided by these languages, also a language behind visual programming environment for novice programmers or professionals must be easy to use & productive.

Java & C# are avoided for some reason too! I wanted to use a dynamic programming language and these languages are static typing, Java is multi-platform, also C# through Mono, but the use of huge number of classes and forcing the use of Object-Orientation, using a verbose language is not right for me. I need a small language, but fast and productive, also I need better control on the Garbage Collector (GC), I need a better one that is designed for fast applications.

Lua is small and fast, but it’s avoided because I need more powerful language for large applications.

PHP is a Web programming language and it’s syntax is very similar to C, this leads to a language not general as I want and not simple as I need to have.

Python & Ruby are more like what I need, but I need something more simple, smaller, faster & productive.

Python and Ruby are Case-Sensitive, the list index start counting from 0, you have to define the function before calling it, Ruby usage of Object-Orientation and message passing is more than what I need and decrease performance, Python syntax (indentation, using self, :, pass & _) is not good for my goals.

All of these languages are successful languages, and very good for their domains, but what I need is a different language that comes with new ideas and intelligent implementation (Innovative, Ready, Simple, Small, Flexiable and Fast).



Lessons/History

History

edit

In Sept. 2013 I started the design and the implementation of the Ring programming language. After 21 months of development, In May 2015 the language Compiler & Virtual Machine were ready for use!

After that i spent three months testing the language again, trying to discover any bug to fix, writing better tests, by the end of August 2015, all know bugs were fixed, Writing many tests and testing automation using batch files and diff.exe helped a lot in getting a stable product.

In 12 September 2015, most of the documentation was written. Before releasing the language i started the marketing by writing a post in Arabic language about it to my facebook profile page asking for contributors interested in the language idea after reading a short description, in the same day i got a lot of emails from developers and friends interested to contribute!

The first version of the language Ring 1.0 is released in January 25, 2016



Lessons/Features

Features

edit

The Ring language comes with the next features

.. tip:: One of the main goals behind the first release is creating a useful language ready for production!

  • Free Open Source (MIT License)
  • Interpreter - Hybrid Implementation (Compiler+VM)
  • Declarative programming on the top of Object-Oriented programming
  • No explicit end for statements (No ; or ENTER is required)
  • A small language (Around 100,000 lines of code)

* The compiler + The Virtual Machine are 15,000 lines of C code * The other 85,000 lines of code are related to libraries! * 10,000 lines of C code * 50,000 lines of C++ code * 25,000 lines of Ring code

  • Written in ANSI C (The code is generated)
  • Developed using Visual Programming (PWCT)
  • Optional Printing for Tokens/Grammar/Byte-Code during execution
  • Portable (Windows, Linux & Mac OS X)
  • Comments (One line & Multi-lines)
  • Not Case-Sensitive
  • Dynamic Typing
  • Weakly typed
  • Lexical Scoping (Global, Local & Object State)
  • Default scope for variables inside functions (Local)
  • Default scope for variables outside functions (global)
  • Garbage Collector - Automatic Memory Management (Escape Analysis and Reference Counting)
  • Structure Programming
  • Rich control structures & Operators
  • For in get item by reference not value, you can read/edit the item
  • Use exit to go outside from more than one loop
  • Procedures/Functions
  • Main Function (optional)
  • Call Function before the definition
  • Recursion
  • Multi-line literals
  • Access (read/write) string letter by index
  • The list index start by 1
  • No keyword to end Functions/Classes/Packages
  • Range operator ex: 1:10 and "a":"z"
  • First Class Variables, Lists, Objects and Functions
  • Store/Copy Lists/Objects by value (Deep Copy)
  • Pass Lists/Objects by reference
  • Native Object-Oriented Support

* Encapsulation * Setter/Getter (optional) * private state (optional) * Instantiation * Polymorphism * Composition * Inheritance (Single Inheritance) * Operator Overloading * Packages

  • using { } to access objects and use attributes/methods as variables/functions
  • Reflection and Meta-programming
  • Clear program structure (Statements then functions then packages & classes)
  • Exception Handling
  • Eval() to execute code during run-time
  • 8-bit clean, work on binary data directly
  • I/O commands
  • Math functions
  • String functions
  • List functions
  • File processing functions
  • Database support (ODBC & MySQL)
  • Security Functions (OpenSSL)
  • Internet Functions (LibCurl)
  • CGI Library (Written in Ring)

* HTTP Get * HTTP Post * File upload * Cookies * URL Encode * HTML Templates * HTML Special Characters * HTML Generation using Functions * HTML Generation using Classes * CRUD Example (using MVC) * Users Example (Register, Login and Check)

  • Extension using C/C++ (Simple API)
  • Embedding the language in C/C++ programs
  • Comes with code generator (Written in Ring) to quickly wrap C/C++ Libraries

* Used to Support Allegro by creating RingAllegro * Used to Support Qt by creating RingQt

  • Create 2D Games (Using the Allegro Library)
  • Create GUI Applications for Desktop and Mobile (Using the Qt Framework)



Lessons/Variables

Variables

edit

To create a new variable, you just need to determine the variable name & value. The value will determine the variable type and you can change the value to switch between the types using the same variable name.

Syntax:

	
	<Variable Name> = <Value>

.. tip::

The operator '=' is used here as an Assignment operator and the same operator can be used in conditions, but for testing equality of expressions.

.. note::

The Variable will contains the real value (not a reference). This means that once you change the variable value, the old value will be removed from memory (even if the variable contains a list or object).


Dynamic Typing

edit

Ring is a dynamic programming language that uses `Dynamic Typing <http://en.wikipedia.org/wiki/Type_system>`_.

	x = "Hello"		# x is a string
	see x + nl
	x = 5			# x is a number (int)
	see x + nl
	x = 1.2 		# x is a number (double)
	see x + nl
	x = [1,2,3,4]		# x is a list
	see x 			# print list items
	x = date()		# x is a string contains date
	see x + nl
	x = time()		# x is a string contains time
	see x + nl
	x = true		# x is a number (logical value = 1)
	see x + nl
	x = false		# x is a number (logical value = 0)
	see x + nl

Deep Copy

edit

We can use the assignment operator '=' to copy variables. We can do that to copy values like strings & numbers. Also, we can copy complete lists & objects. The assignment operator will do a complete duplication for us. This operation called `Deep Copy <http://en.wikipedia.org/wiki/Object_copy#Deep_copy>`_


	list = [1,2,3,"four","five"]
	list2 = list
	list = []
	See list	# print the first list - no items to print
	See "********" + nl
	See list2	# print the second list - contains 5 items

Weakly Typed

edit

Ring is a `weakly typed language <http://en.wikipedia.org/wiki/Strong_and_weak_typing>`_, this means that the language can automatically convert between data types (like string & numbers) when that conversion make sense.

Rules:

	<NUMBER> + <STRING> --> <NUMBER>
	<STRING> + <NUMBER> --> <STRING>

.. note::

The same operator '+' can be used as an arithmetic operator or for string concatenation.

Example:

	x = 10			# x is a number
	y = "20"		# y is a string
	sum = x + y		# sum is a number (y will be converted to a number)
	Msg = "Sum = " + sum 	# Msg is a string (sum will be converted to a string)
	see Msg + nl



Lessons/Operators

Operators

edit

In this chapter we will introduce the operators provided by the Ring programming language.

Arithmetic Operators

edit

The next table presents all of the arithmetic operators provided by the Ring language. Assume variable X=50 and variable Y=10 then:

+------------+---------------+----------+---------+
| Operator   | Description   | Example  | Result  |
+============+===============+==========+=========+
| +          |  Add          |  x+y     |  60     |
+------------+---------------+----------+---------+
| -          |	Subtract     |	x-y     |  40     |
+------------+---------------+----------+---------+
| *          |  Multiplies   |	x*y     |  500    |
+------------+---------------+----------+---------+
| /          |  Divide	     |	x/y     |  5      |
+------------+---------------+----------+---------+
| %          |  Modulus	     |	x%y     |  0      | 
+------------+---------------+----------+---------+
| ++         |  Increment    |	x++     |  51     |
+------------+---------------+----------+---------+
| --         |  Decrement    |	x--     |  49     |
+------------+---------------+----------+---------+

Relational Operators

edit

The next table presents all of the relational operators provided by the Ring language. Assume variable X=50 and variable Y=10 then:

+------------+---------------------+-------------+---------+
| Operator   | Description         | Example     | Result  |
+============+=====================+=============+=========+
| =          |  Equal	           |    x = y    |  False  |
+------------+---------------------+-------------+---------+
| !=         |	Not Equal          |	x != y   |  True   |
+------------+---------------------+-------------+---------+
| >          |  Greater than       |	x > y    |  True   |
+------------+---------------------+-------------+---------+
| <          |  Less than          |	x < y    |  False  |
+------------+---------------------+-------------+---------+
| >=         |  Greater or Equal   |	x >= y   |  True   | 
+------------+---------------------+-------------+---------+
| <=         |  Less than or Equal |	x <= y   |  False  |
+------------+---------------------+-------------+---------+

Logical Operators

edit

The next table presents all of the logical operators provided by the Ring language. Assume variable X=True and variable Y=False then:

+------------+---------------------+-------------+---------+
| Operator   | Description         | Example     | Result  |
+============+=====================+=============+=========+
| and	     |  Logical AND        |    x and y  |  False  |
+------------+---------------------+-------------+---------+
| or         |	Logical OR         |	x or y   |  True   |
+------------+---------------------+-------------+---------+
| not	     |  Logical Not        |	not x    |  False  |
+------------+---------------------+-------------+---------+


Bitwise Operators

edit

The next table presents all of the bitwise operators provided by the Ring language. Assume variable X=8 and variable Y=2 then:

+------------+-----------------------------+-------------+---------+
| Operator   | Description                 | Example     | Result  |
+============+=============================+=============+=========+
| &          |  Binary AND                 |    x & y    |  0      |
+------------+-----------------------------+-------------+---------+
| |          |	Binary OR                  |	x | y    |  10     |
+------------+-----------------------------+-------------+---------+
| ^          |  Binary XOR                 |	x ^ y    |  10     |
+------------+-----------------------------+-------------+---------+
| ~          |  Binary Ones Complement 	   |	~x       |  -9     |
+------------+-----------------------------+-------------+---------+
| <<         |  Binary Left Shift          |	x << y   |  32     | 
+------------+-----------------------------+-------------+---------+
| >>         |  Binary Right Shift         |	x >> y   |  2      |
+------------+-----------------------------+-------------+---------+

Assignment Operators

edit

The next table presents all of the assignment operators provided by the Ring language.

Assume variable X=8 then:

+------------+-----------------------------+-------------+---------+
| Operator   | Description                 | Example     | Result  |
+============+=============================+=============+=========+
| =          |  Assignment                 |    x = 10   |  x=10   |
+------------+-----------------------------+-------------+---------+
| +=         |	Add AND assignment         |	x += 5   |  x=13   |
+------------+-----------------------------+-------------+---------+
| -=	     |  Subtract AND assignment    |	x -= 3   |  x=5    |
+------------+-----------------------------+-------------+---------+
| *=         |  Multiply AND assignment    |	x *= 2   |  x=16   |
+------------+-----------------------------+-------------+---------+
| /=         |  Divide AND assignment      |	x /= 3   |  x=2.67 |
+------------+-----------------------------+-------------+---------+
| %=         |  Modulus AND assignment     |	x %= 2   |  x=0    | 
+------------+-----------------------------+-------------+---------+
| <<=        |	Left shift AND assignment  |	x <<= 2  |  x=32   |
+------------+-----------------------------+-------------+---------+
| >>=	     |  Right shift AND assignment |	x >>= 2  |  x=2    |
+------------+-----------------------------+-------------+---------+
| &=         |  Bitwise AND assignment     |	x &= 4   |  x=0    |
+------------+-----------------------------+-------------+---------+
| |=         |  Bitwise OR and assignment  |	x |= 3   |  x=11   |
+------------+-----------------------------+-------------+---------+
| ^=         |  Bitwise XOR and assignment |	x ^= 4   |  x=12   |
+------------+-----------------------------+-------------+---------+

Misc Operators

edit
==============	======================================================================
Operator        Description
==============	======================================================================
:literal        using : before identifier mean literal
Start:End       create list contains items from start to end
[list items]    define list items
list[index]     access list item
obj.name        using the dot operator to access object members (attributes/methods).
obj {stmts}     execute statements with direct access to object attributes & methods
func(para,...)  call function using parameters separated by comma
==============	======================================================================

Operators Precedence

edit

The next table present operators from higher precedence (Evaluated first) to lower precedence.

+----------------------------------------------------------------+
| Operator                                                       |
+================================================================+
| .  []   ()     {}                                              |
+----------------------------------------------------------------+
| -  ~  :Literal  [list items]                                   |
+----------------------------------------------------------------+
| ++   --                                                        |
+----------------------------------------------------------------+
| Start:End                                                      |
+----------------------------------------------------------------+
| * /  %                                                         |
+----------------------------------------------------------------+
| + -                                                            |
+----------------------------------------------------------------+
| <<   >>                                                        |
+----------------------------------------------------------------+
| &                                                              |
+----------------------------------------------------------------+
| \|  ^	                                                         |
+----------------------------------------------------------------+
| <  >  <=  >=                                                   |
+----------------------------------------------------------------+
| =  !=                                                          |
+----------------------------------------------------------------+
| not                                                            |
+----------------------------------------------------------------+
| and   or                                                       |
+----------------------------------------------------------------+
| Assignment = += -= \*= /= %=>>= <<= &= ^= \|=                  |
+----------------------------------------------------------------+

Example:

	See 3+5*4	# prints 23



Lessons/Control Structures

Control Structures

edit

In this chapter we are going to learn about the control structures provided by the Ring programming language.

Branching

edit
  • If Statement

Syntax:

	if Expression
		Block of statements
	but Expression
		Block of statements
	else
		Block of statements
	ok

Example:

	see " 
		Main Menu
		---------
		(1) Say Hello
		(2) About
		(3) Exit

	    " give nOption

	if nOption = 1	see "Enter your name : " give name see "Hello " + name + nl
	but nOption = 2 see "Sample : using if statement" + nl
	but nOption = 3 bye
	else see "bad option..." + nl
	ok
  • Switch Statement

Syntax:

	switch Expression
	on Expression
		Block of statements
	other
		Block of statements
	off

Example:

	See " 
		Main Menu
		---------
		(1) Say Hello
		(2) About
		(3) Exit

	    " Give nOption

	Switch nOption
	On 1 See "Enter your name : " Give name See "Hello " + name + nl
	On 2 See "Sample : using switch statement" + nl
	On 3 Bye
	Other See "bad option..." + nl
	Off


Looping

edit
  • While Loop

Syntax:

	while Expression
		Block of statements
	end

Example:

	While True

		See " 
			Main Menu
			---------
			(1) Say Hello
			(2) About
			(3) Exit

		    " Give nOption

		Switch nOption
		On 1 
			See "Enter your name : " 
			Give name 
			See "Hello " + name + nl
		On 2 
			See "Sample : using while loop" + nl
		On 3 
			Bye
		Other 
			See "bad option..." + nl
		Off
	End
  • For Loop

Syntax:

	for identifier=expression to expression [step expression]
		Block of statements
	next

Example:

	# print numbers from 1 to 10
	for x = 1 to 10	 see x + nl  next

Example:

	# Dynamic loop
	See "Start : " give nStart       
	See "End   : " give nEnd
	See "Step  : " give nStep
	For x = nStart to nEnd Step nStep
		see x + nl
	Next

Example:

	# print even numbers from 0 to 10
	for x = 0 to 10 step 2
		see x + nl
	next

Example:

	# print even numbers from 10 to 0
	for x = 10 to 0 step -2
		see x + nl
	next
  • For in Loop

Syntax:

	for identifier in List/String  [step expression]
		Block of statements
	next

Example:

	aList = 1:10	# create list contains numbers from 1 to 10
	for x in aList  see x + nl  next  # print numbers from 1 to 10

Using The Step option with For in

edit

We can use the Step option with For in to skip number of items in each iteration

Example:

	aList = 1:10	# create list contains numbers from 1 to 10
	# print odd items inside the list
	for x in aList step 2
		see x + nl  
	next

Using For in to modify lists

edit

When we use (For in) we get items by reference.

This means that we can read/edit items inside the loop.

Example:

	aList = 1:5	# create list contains numbers from 1 to 5
	# replace list numbers with strings
	for x in aList  
		switch x
		on 1  x = "one"
		on 2  x = "two"
		on 3  x = "three"
		on 4  x = "four"
		on 5  x = "five"
		off
	next
	see aList	# print the list items

Do Again Loop

edit

Syntax:

	
	do
		Block of statements
	again expression

Example:

	x = 1 
	do 
		see x + nl 
		x++ 
	again x <= 10


Exit Command

edit

Used to go outside one or more of loops.


Syntax:

	exit [expression]	# inside loop


Example:

	for x = 1 to 10
		see x + nl
		if x = 5 exit ok
	next

Exit from two loops

edit

The next example presents how to use the exit command to exit from two loops in one jump.

Example:

	for x = 1 to 10
		for y = 1 to 10
			see "x=" + x + " y=" + y + nl
			if x = 3 and y = 5
				exit 2	   # exit from 2 loops 
			ok
		next
	next
  • Loop Command

Used to jump to the next iteration in the loop.

Syntax:

	loop [expression]	# inside loop

Example:

	for x = 1 to 10
		if x = 3
			see "Number Three" + nl
			loop
		ok
		see x + nl
	next

Exit/Loop inside sub functions

edit

While we are inside a loop, we can call a function then use the exit and/or loop command inside that function and the command will work on the outer loop.

Example:

	# print numbers from 1 to 10 except number 5.

	for x = 1 to 10
		ignore(x,5)
		see x + nl
	next

	func ignore x,y
		if x = y
			loop
		ok


Short-circuit evaluation

edit

The logical operators and/or follow the `short-circuit evaluation <http://en.wikipedia.org/wiki/Short-circuit_evaluation>`_.

If the first argument of the AND operator is zero, then there is no need to evaluate the second argument and the result will be zero.

If the first argument of the OR operator is one, then there is no need to evaluate the second argument and the result will be one.

Example:

	/* output
	** nice 
	** nice 
	** great	
	*/

	x = 0 y = 10

	if (x = 0 and nice()) and (y = 10 and nice())
		see "great" + nl
	ok

	func nice  see "nice" + nl   return 1

Example:

	# No output

	x = 0 y = 10

	if (x = 1 and nice()) and (y = 10 and nice())
		see "great" + nl
	ok

	func nice  see "nice" + nl   return 1

Example:

	/* output 
	** nice
	** great
	*/
 
	x = 0 y = 10

	if (x = 0 and nice()) or (y = 10 and nice())
		see "great" + nl
	ok

	func nice  see "nice" + nl  return 1

Comments about evaluation

edit
  • True, False, nl & NULL are variables defined by the language
  • True = 1
  • False = 0
  • nl = new line
  • NULL = empty string = ""
  • Everything evaluates to true except 0 (False).

Example:

	# output = message from the if statement

	if 5 	# 5 evaluates to true because it's not zero (0).
		see "message from the if statement" + nl
	ok



Lessons/Getting Input

Getting Input

edit

We can get input from the keyboard using

  • The Give Command
  • The GetChar() Function
  • The Input() Function

Give Command

edit

Syntax:

	Give VariableName

Example:

	See "Enter the first number : " Give nNum1
	See "Enter the second number : " Give nNum2
	See "Sum : " + ( 0 + nNum1 + nNum2 )

Output:

	Enter the first number : 3
	Enter the second number : 4
	Sum : 7

GetChar() Function

edit

We can get one character from the standard input using the GetChar() function

Syntax:

	GetChar() ---> Character

Example:

	While True
		See "
			Main Menu
			(1) Say Hello
			(2) Exit
		    " 
		Option = GetChar()
		GetChar() GetChar()  # End of line

		# the previous two lines can be replaced with the next line
		# Give Option

		if Option = 1
			see "Enter your name : " give cName 
			see "Hello " + cName
		else
			bye
		ok
	End

Input() Function

edit

We can get input from the keyboard using the Input() function

Syntax:

	Input(nCount) ---> string

The function will wait until nCount characters (at least) are read

Example:

	See "Enter message (30 characters) : " cMsg = input(30)
	See "Message : " + cMsg



Lessons/Functions

Functions

edit

In this chapter we are going to learn about the next topics :-

  • Define functions
  • Call functions
  • Declare parameters
  • Send parameters
  • Main Function
  • Variables Scope
  • Program structure
  • Return Value
  • Recursion

Define Functions

edit

To define new function

Syntax:

	func <function_name> [parameters]
		Block of statements

.. note:: No keyword is required to end the function definition.


Example:

	func hello
		see "Hello from function" + nl

Call Functions

edit

To call function without parameters, we type the function name then ()

.. tip:: We can call the function before the function definition and the function code.

Example:

	hello()

	func hello
		see "Hello from function" + nl


Example:

	first()  second()

	func first   see "message from the first function" + nl

	func second  see "message from the second function" + nl

Declare parameters

edit

To declare the function parameters, after the function name type the list of parameters as a group of identifiers separated by comma.

Example:

	func sum x,y
		see x+y+nl

Send Parameters

edit

To send parameters to function, type the parameters inside () after the function name

Syntax:

	funcname(parameters)

Example:

	/* output
	** 8
	** 3000
	*/

	sum(3,5) sum(1000,2000)

	func sum x,y see x+y+nl


Main Function

edit

Using the Ring programming language, the Main Function is optional, when it's defined, it will be executed after the end of other statements.

if no other statements comes alone, the main function will be the first `entry point <http://en.wikipedia.org/wiki/Entry_point>`_

Example:

	# this program will print the hello world message first then execute the main function

	See "Hello World!" + nl

	func main
		see "Message from the main function" + nl

Variables Scope

edit

The Ring programming language uses `lexical scoping <http://en.wikipedia.org/wiki/Scope_%28computer_science%29#Lexical_scope_vs._dynamic_scope>`_ to determine the scope of a variable.

Variables defined inside functions (including function parameters) are local variables. Variables defined outside functions (before any function) are global variables.

Inside any function we can access the variables defined inside this function beside the global variables.

Example:

	# the program will print numbers from 10 to 1

	x = 10 				# x is a global variable.

	func main

		for t = 1 to 10		# t is a local variable
			mycounter()	# call function
		next

	func mycounter

		see x + nl		# print the global variable value
		x--			# decrement

.. note:: Using the main function before the for loop declare the t variable as a local variable, It's recommended to use the main functions instead of typing the instructions directly to set the scope of the new variables to local.


Program Structure

edit
+--------------------------------+
| Source Code File Sections	 |
+================================+
| Load Files			 |
+--------------------------------+
| Statements and Global Variables|
+--------------------------------+
| Functions 			 |
+--------------------------------+
| Packages and Classes		 |
+--------------------------------+

The application maybe one or more of files.

to include another source file in the project, just use the load command.


Syntax:

	Load  "filename.ring"

Example:

	# File : Start.ring

	Load "sub.ring"

	sayhello("Mahmoud")
	# File : sub.ring

	func sayhello cName
		see "Hello " + cName + nl

Return Value

edit

The function can return a value using the Return command.

Syntax:

	Return [Expression]

.. tip:: the Expression after the return command is optional and we can use the return command to end the function execution without returning any value.

.. note:: if the function doesn't return explicit value, it will return NULL (empty string = "" ).

Example:

	if novalue() = NULL	
		See "the function doesn't return a value" + nl
	ok

	func novalue

Recursion

edit

The Ring programming language support `Recursion <http://en.wikipedia.org/wiki/Recursion_%28computer_science%29>`_ and the function can call itself using different parameters.

Example:

	see fact(5)  	# output = 120

	func fact x if x = 1 return 1 else return x * fact(x-1) ok



Lessons/Lists

Lists

edit

In this chapter we are going to learn how to deal with lists.

Create Lists

edit

We can create new lists by defining the list items inside square bracts.

Example:

	aList = [1,2,3,4,5]

Also we can create new lists using the : operator


Example:

	aList = 1:5
	aList2 = "a":"z"

Also we can create lists using the list() function

Syntax:

	list = list(size)

Example

	aList = list(10)	# aList contains 10 items

.. note:: the list index start from 1

Add Items

edit

To add new items to the list, we can use the Add() function.

Syntax:

	Add(List,Item)


Example:

	aList = ["one","two"]
	add(aList,"three")

Also we can do that using the + operator.

Syntax:

	List + item

Example:

	aList = 1:10	# create list contains numbers from 1 to 10
	aList + 11	# add number 11 to the list
	see aList	# print the list

Get List Size

edit

We can get the list size using the len() function

Syntax:

	Len(List)

Example:

	aList = 1:20  see len(aList)  # print 20

Delete Item From List

edit

To delete an item from the list, we can use the del() function

Syntax:

	del(list,index)

Example:

	aList = ["one","two","other","three"]
	Del(aList,3)	# delete item number three
	see aList   	# print one two three

Get List Item

edit

To get an item from the list, we uses the next syntax

	List[Index]

Example:

	aList = ["Cairo","Riyadh"]
	see "Egypt : " + aList[1] + nl +
	    "KSA   : " + aList[2] + nl

Set List Item

edit

To set the value of an item inside the list, we can use the next syntax

	List[Index] = Expression

Example:

	aList = list(3)	# create list contains three items
	aList[1] = "one" aList[2] = "two" aList[3] = "three"
	see aList
edit

To find an item inside the list we can use the find() function

Syntax:

	Find(List,ItemValue) ---> Item Index
	Find(List,ItemValue,nColumn) ---> Search in nColumn, returns the Item Index

Example:

	aList = ["one","two","three","four","five"]
	see find(aList,"three")		# print 3

Example:

	mylist = [["one",1],
		  ["two",2],
		  ["three",3]]

	see find(mylist,"two",1) + nl		# print 2
	see find(mylist,2,2) + nl		# print 2

Also we can use the binarysearch() function to search in sorted list.

Syntax:

	BinarySearch(List,ItemValue) ---> Item Index
	BinarySearch(List,ItemValue,nColumn) ---> Search in nColumn, returns the Item Index

Example:

	aList = ["one","two","three","four","five"]
	aList = sort(aList)
	see binarysearch(aList,"three")

Output:

	five
	four
	one
	three
	two
	4

Sort

edit

We can sort the list using the sort() function.

Syntax:

	Sort(List) ---> Sorted List
	Sort(List,nColumn) ---> Sorted List based on nColumn

Example:

	aList = [10,12,3,5,31,15]
	aList = sort(aList) see aList # print 3 5 10 12 15 31

We can sort list of strings

Example:

	mylist = ["mahmoud","samir","ahmed","ibrahim","mohammed"]
	see mylist	   	  # print list before sorting
	mylist = sort(mylist)	  # sort list
	see "list after sort"+nl
	see mylist		  # print ahmed ibrahim mahmoud mohammed samir

We can sort a list based on a specific column.

Example:

	aList = [ ["mahmoud",15000] ,
		  ["ahmed", 14000 ] ,
		  ["samir", 16000 ] ,
		  ["mohammed", 12000 ] ,
	 	  ["ibrahim",11000 ] ]

	aList2 = sort(aList,1)
	see aList2

Output:

	ahmed
	14000
	ibrahim
	11000
	mahmoud
	15000
	mohammed
	12000
	samir
	16000

Reverse

edit

We can reverse a list using the reverse() function.

Syntax:

	Reverse(List) ---> Reversed List

Example:

	aList = [10,20,30,40,50]
	aList = reverse(aList)
	see aList 	# print 50 40 30 20 10

Insert Items

edit

To insert an item in the list we can use the insert() function.

Syntax:

	Insert(List,Index,Item)

The inserted item will be after the index

Example:

	aList = [1,2,4,5]
	insert(aList,2,3)
	see aList	  # print 1 2 3 4 5

Nested Lists

edit

The list may contain other lists

Example:

	aList = [ 1 , [10,20,30] , 5 , [100,1000,5000] ]
	aList2 = [
	"one","two", 
	[3,4],
	[20,30], ["three",
		  "four",
		  "five",[100,200,300]
                 ]
	]
	
	see aList[2] 	 	# print 10 20 30
	see aList[4][3] + nl 	# print 5000
	see aList2[5][2] + nl 	# print four
	see aList2[5][4][3]	# print 300

Copy Lists

edit

We can copy lists (including nested lists) using the Assignment operator.

Example:

	aList = [
	"one","two", 
	[3,4],
	[20,30], ["three",
		  "four",
		  "five",[100,200,300]
                 ]
	]

	aList2 = aList		# Copy aList to aList2
	aList2[5] = "other"	# modify item number five
	see aList2[5] + nl	# print other
	see aList[5]		# print three four five 100 200 300

First-class lists

edit

Lists are `first-class citizens <http://en.wikipedia.org/wiki/First-class_citizen>`_ where we can store lists in variables, pass lists to functions, and return lists from functions.

Example:

	aList = duplicate( [1,2,3,4,5] )
	see aList[10] + nl		  # print 5

	see mylist()			  # print 10 20 30 40 50
	
	func duplicate list
		nMax = len(list)
		for x = 1 to nMax
			list + list[x]
		next
		return list

	func mylist return [10,20,30,40,50]

Using Lists during definition

edit

We can use the list items while we are defining the list for the first time.

Example:

	aList = [ [1,2,3,4,5] , aList[1] , aList[1] ]
	see aList	# print 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5


Passing Lists to Functions

edit

Lists are passed to functions by reference, This means that the called function will work on the same list and can modify it.

Example:

	func main
		aList = [1,2,3,4,5]	# create list, local in function main
		myfunc(aList)		# call function, pass list by reference
		see aList		# print 1 2 3 4 5 6 7 8 9 10

	func myfunc list
		list + [6,7,8,9,10]

Access List Items by String Index

edit

Instead of using numbers to determine the item index when we get item value or set item value, We can access items using string index if the item is a list contains two items and the first item is a string.

Example:

	aList = [ ["one",1] , ["two",2] , ["three",3] ]
	see aList["one"] + nl +
	    aList["two"] + nl +
	    aList["three"] 	# print 1 2 3

This type of lists can be defined in a better syntax using the : and = operators.

Example:

	aList = [ :one = 1 , :two = 2 , :three = 3 ]
	see aList["one"] + nl +
	    aList["two"] + nl +
	    aList["three"] + nl	# print 1 2 3
	see aList[1]		# print one 1

.. tip:: using : before identifier (one word) means literal

.. note:: using = inside list definition create a list of two items where the first item is the left side and the second item is the right side.

We can add new items to the list using the string index

Example:

	aList = []
	aList["Egypt"] = "Cairo"
	aList["KSA"] = "Riyadh"
	see aList["Egypt"] + nl + 	# print Cairo
	    aList["KSA"] + nl		# print Riyadh

Passing Parameters Using List

edit

This type of lists is very good for passing parameters to functions Where the order of parameters will not be important (we can change the order).

Also some parameters maybe optional.

Example:

	myconnect (  [ :server = "myserver.com" , :port = 80 , 
                       :username = "mahmoud" , :password = "password" ] ) 

	func myconnect mypara
	
		# print connection details
		see "User Name : " + mypara[:username] + nl +
		    "Password  : " + mypara[:password] + nl +
                    "Server    : " + mypara[:server] + nl +
                    "Port      : " + mypara[:port]


Lessons/Strings

Strings

edit

In this chapter we are going to learn about strings creation and manipulation.

String Literals

edit

Syntax:

	cStr = "This is a string"
	cStr2 = 'Another string'
	cStr3 = :JustAnotherString
	cStr4 = `Yet "another" 'string' ! `

Get String Length

edit

We can get the string length (letters count inside a string) using the len() function

Syntax:

	len(string) ---> string length

Example:

	cStr = "How are you?"
	see cStr + nl
	see "String size : " + len(cStr) + nl

Convert Letters Case

edit

Syntax:

	lower(string) ---> convert string letters to lower case
	upper(string) ---> convert string letters to UPPER case

Example:

	cStr = "Welcome To The Ring Programming Language"
	see cStr + nl + upper(cStr) + nl + lower(cStr)

Access String Letters

edit

We can access a letter inside a string by the letter index

Syntax:

	string[index] ---> get string letter
	string[index] = letter  # set string letter

Example:

	# print user name letter by letter (each letter in new line)

	See "Hello, Enter your name : " give cName
	for x = 1 to len(cName)
		see nl + cName[x]
	next


We can use for in to get string letters.


Example:

	# print user name letter by letter (each letter in new line)
	See "Hello, Enter your name : " give cName
	for x in cName
		see nl + x
	next

We can modify the string letters

Example:

	# convert the first letter to UPPER case
	See "Enter your name : " give cName
	cName[1] = upper(cName[1])
	see "Hello " + cName

Left() Function

edit

We can get a specified number of characters from a string using the Left() function.

The starting position is 1.

Syntax:

	Left(string,count)

Example:

	see left("Hello World!",5) # print Hello

Right() Function

edit

We can get a specified number of characters from a string using the Right() function.

The starting position is the last character on the right.

Syntax:

	Right(string,count)

Example:

	see Right("Hello World!",6) # print World!

Trim() Function

edit

We can remove all leading and trailing spaces from a string using the Trim() function.

Syntax:

	trim(string)

Example:

	cMsg = "     Welcome      "
	see trim(cMsg)			# print Welcome

Copy() Function

edit

We can duplicate a string more than one time using the copy() function.

Syntax:

	copy(string,count) ---> string replicqated count times

Example

	see copy("***hello***",3) # print ***hello******hello******hello***

Lines() Function

edit

We can count the number of lines inside a string using the Lines() function.

Syntax:

	lines(string) ---> Number of lines inside the string

Example:

	cStr = "Hello
	How are you?
	are you fine?"
	see lines(cStr)		# print 3

Substr() Function

edit

We can work on sub strings inside a string using the substr() function. Using Substr() we can

  • Find substring
  • Get substring from position to end
  • Get Number of characters from position
  • Transform Substring To Another Substring

Find substring

edit

Syntax:

	substr(string,substring)  ---> the starting position of substring in string

Example:

	cStr = "Welcome to the Ring programming language"
	see substr(cStr,"Ring")		# print 16

Get substring from position to end

edit

Syntax:

	substr(string,position)  ---> Get substring starting from position to end

Example:

	cStr = "Welcome to the Ring programming language"
	nPos = substr(cStr,"Ring")	# nPos = 16
	see substr(cStr,nPos)		# print Ring programming language

Get Number of Characters From Position

edit

Syntax:

	substr(string,position,count)  ---> Get characters starting from position

Example:

	cStr = "Welcome to the Ring programming language"
	nPos = substr(cStr,"Ring")	# nPos = 16
	see substr(cStr,nPos,4)		# print Ring

Transform Substring To Another Substring

edit

Syntax:

	substr(string,substring,newsubstring)  ---> Transformed string (Match case)
	substr(string,substring,newsubstring,1)  ---> Transformed string (Ignore case)

Example:

	cStr = "Welcome to the New programming language"
	see substr(cStr,"New","Ring") + nl  # print Welcome to the Ring programming language 
	see substr(cStr,"new","Ring",1)+ nl # print Welcome to the Ring programming language

strcmp() Function

edit

We can compare between two strings using the strcmp() function.

Syntax:

	strcmp(cString1,cString2) ---> value = 0 if cString1 = cString2
				       value < 0 if cString1 < cString2
				       value > 0 if cString1 > cString2

Example:

	see strcmp("hello","hello") + nl +
	    strcmp("bcd","abc") + nl

Output:

	0
	-1
	1

str2list() and list2str() Functions

edit

We can convert string lines to list items using the str2list() function. Also we can convert the list to a string using list2str() function.

Syntax:

	str2list(string) ---> list contains the string lines 
	list2str(list)   ---> string contains the list items

Example:

	/* output:
	** Items : 4
	** Item : Hello
	** Item : How are you ?
	** Item : are you fine ?
	** Item : ok
	** list2Str result = Hello
	** How are you ?
	** are you fine ?
	** ok
	** Done
	*/

	mystr = "Hello
	How are you ?
	are you fine ?
	ok"

	mylist = str2list(mystr)
	see "Items : " + len(mylist) + nl

	for x in mylist
		see "Item : " + x + nl
	next

	newstr = list2str(mylist)
	see "list2Str result = " + newstr

	if mystr = newstr
		see nl + "Done"
	else
		see nl + "Error!"
	ok



Lessons/Date and Time

Date and Time

edit

In this chapter we are going to learn about the date and time functions.



Clock() Function

edit

Syntax:

	 Clock() ---> The number of clock ticks from program start

Example:

	
	See "Calculate performance" + nl
	t1 = clock()
	for x = 1 to 1000000 next
	see clock() - t1



Time() Function

edit

We can get the system time using the Time() function.

Example:

	
	See "Time : " + time()



Date() Function

edit

We can get the date using the Date() function.

Syntax:

	 Date() ---> String represent the date "dd/mm/yyyy"

Example:

	See "Date : " + date()  # Date : 24/05/2015



TimeList() Function

edit

We can print the date and the time information using the TimeList() function.

Syntax:

	TimeList() ---> List contains the time and date information.

The next table presents the list items

======  ===================================
index	value
======	===================================
1		abbreviated weekday name 
2		full weekday name
3		abbreviated month name
4		full month name
5		Date & Time
6		Day of the month
7		Hour (24)
8		Hour (12)
9		Day of the year
10		Month of the year
11		Minutes after hour
12		AM or PM
13		Seconds after the hour
14		Week of the year (sun-sat)
15		day of the week
16		date
17		time
18		year of the century		
19		year
20		time zone
21		percent sign
======	===================================

Example:

	/* Output:
	** Sun			abbreviated weekday name 
	** Sunday		full weekday name
	** May			abbreviated month name
	** May			full month name
	** 05/24/15 09:58:38	Date & Time
	** 24			Day of the month
	** 09			Hour (24)
	** 09			Hour (12)
	** 144			Day of the year
	** 05			Month of the year
	** 58			Minutes after hour
	** AM			AM or PM
	** 38			Seconds after the hour
	** 21			Week of the year (sun-sat)
	** 0			day of the week
	** 05/24/15		date
	** 09:58:38		time
	** 15			year of the century		
	** 2015			year
	** Arab Standard Time	time zone
	** %			percent sign
	*/
	
	See TimeList()

Example:

	See "Day Name : " + TimeList()[2]	# Sunday

Example:

	See "Month Name : " + TimeList()[4]	# May



AddDays() Function

edit

Syntax:

	AddDays(cDate,nDays) ---> Date from cDate and after nDays

Example:

	cDate = date()
	see cDate + nl			# 24/05/2015
	cDate = adddays(cDate,10)
	see cDate + nl			# 03/06/2015



DiffDays() Function

edit

Syntax:

	DiffDays(cDate1,cDate2) ---> number of days (Date1 - Date2)

Example:

	cDate1 = date()
	see cDate1 + nl						# 24/05/2015
	cDate2 = adddays(cDate1,10)
	see cDate2 + nl						# 03/06/2015
	see "DiffDays = " + diffdays(cDate1,cDate2) + nl	# -10
	see "DiffDays = " + diffdays(cDate2,cDate1) + nl	# 10



Lessons/Check Data Type and Conversion

Check Data Type and Conversion

edit

In this chapter we are going to learn about the functions that can be used for

  • Checking Data Type
  • Checking Character
  • Conversion



Check Data Type

edit

The next functions can be used to check the data type

  • isstring()
  • isnumber()
  • islist()
  • type()
  • isnull()



IsString() Function

edit

Using the IsString() function we can know if the value is a string or not

Syntax:

	IsString(value) ---> 1 if the value is a string or 0 if not

Example:

	see isstring(5) + nl +		# print 0
	    isstring("hello") + nl	# print 1



IsNumber() Function

edit

Using the IsNumber() function we can know if the value is a number or not

Syntax:

	IsNumber(value) ---> 1 if the value is a number or 0 if not

Example:

	see isnumber(5) + nl +		# print 1
	    isnumber("hello") + nl	# print 0



IsList() Function

edit

Using the IsList() function we can know if the value is a list or not

Syntax:

	IsList(value) ---> 1 if the value is a list or 0 if not

Example:

	see islist(5) + nl +		# print 0
	    islist("hello") + nl +	# print 0
	    islist([1,3,5]) 		# print 1

pair: Data Type; Type()

Type() Function

edit

We can know the type of a value using the Type() Function.


Syntax:

	Type(value) ---> The Type as String

Example:

	    see Type(5) + nl +		# print NUMBER
	    Type("hello") + nl +	# print STRING
	    Type([1,3,5]) 		# print LIST



IsNULL() Function

edit

We can check the value to know if it's null or not using the IsNULL() function

Syntax:

	IsNULL(value) ---> 1 if the value is NULL or 0 if not

Example:

	    see isnull(5) + nl +	# print 0
	    isnull("hello") + nl +	# print 0
	    isnull([1,3,5]) + nl +	# print 0
	    isnull("") + nl +		# print 1
	    isnull("NULL")		# print 1



Check Character

edit

The next functions can be used to check character

  • isalnum()
  • isalpha()
  • iscntrl()
  • isdigit()
  • isgraph()
  • islower()
  • isprint()
  • ispunct()
  • isspace()
  • isupper()
  • isxdigit()

IsAlNum() Function

edit

We can test a character or a string using the IsAlNum() Function

Syntax:

	IsAlNum(value) ---> 1 if the value is digit/letter or 0 if not

Example:

	see isalnum("Hello") + nl +	# print 1
	    isalnum("123456") + nl +	# print 1
	    isalnum("ABCabc123") + nl +	# print 1
	    isalnum("How are you")  	# print 0 because of spaces

IsAlpha() Function

edit

We can test a character or a string using the IsAlpha() Function

Syntax:

	IsAlpha(value) ---> 1 if the value is a letter or 0 if not

Example:

	see isalpha("Hello") + nl +	# print 1
	    isalpha("123456") + nl +	# print 0
	    isalpha("ABCabc123") + nl +	# print 0
	    isalpha("How are you")  	# print 0

IsCntrl() Function

edit

We can test a character or a string using the IsCntrl() Function

Syntax:

	IsCntrl(value) ---> 1 if the value is a control character (no printing position) or 0 if not

Example:

	See iscntrl("hello") + nl +	# print 0 
	    iscntrl(nl)			# print 1

IsDigit() Function

edit

We can test a character or a string using the IsDigit() Function

Syntax:

	IsDigit(value) ---> 1 if the value is a digit or 0 if not

Example:

	see isdigit("0123456789") + nl +	# print 1
	    isdigit("0123a") 			# print 0

IsGraph() Function

edit

We can test a character or a string using the IsGraph() Function

Syntax:

	IsGraph(value) ---> 1 if the value can be printed (Except space) or 0 if not

Example:

	see isgraph("abcdef") + nl +	# print 1
	    isgraph("abc def") 		# print 0


IsLower() Function

edit

We can test a character or a string using the IsLower() Function

Syntax:

	IsLower(value) ---> 1 if the value is lowercase letter or 0 if not

Example:

	see islower("abcDEF") + nl + 	# print 0
	    islower("ghi")		# print 1


IsPrint() Function

edit

We can test a character or a string using the IsPrint() Function

Syntax:

	IsPrint(value) ---> 1 if the value occupies a printing position or 0 if not

Example:

	see isprint("Hello") + nl + 		# print 1
	    isprint("Nice to see you") + nl +   # print 1
	    isprint(nl)				# print 0


IsPunct() Function

edit

We can test a character or a string using the IsPunct() Function

Syntax:

	IsPunct(value) ---> 1 if the value is a punctuation character or 0 if not

Example:

	see ispunct("hello") + nl +	# print 0
	    ispunct(",") 		# print 1


IsSpace() Function

edit

We can test a character or a string using the IsSpace() Function

Syntax:

	IsSpace(value) ---> 1 if the value is a white-space or 0 if not

Example:

	see isspace("   ") + nl +	# print 1
	    isspace("test") 		# print 0


IsUpper() Function

edit

We can test a character or a string using the IsUpper() Function

Syntax:

	IsUpper(value) ---> 1 if the value is an uppercase alphabetic letter or 0 if not

Example:

	see isupper("welcome") + nl +	 # print 0 
	    isupper("WELCOME") 		 # print 1


IsXdigit() Function

edit

We can test a character or a string using the IsXdigit() Function

Syntax:

	IsXdigit(value) ---> 1 if the value is a hexdecimal digit character or 0 if not

Example:

	see isxdigit("0123456789abcdef") + nl +  # print 1
	    isxdigit("123z") 			 # print 0



Conversion

edit

The next functions can be used for conversion

  • number()
  • string()
  • ascii()
  • char()
  • hex()
  • dec()
  • str2hex()
  • hex2str()

Number() Function

edit

We can convert strings to numbers using the Number() function or the + operator.

Syntax:

	Number(string) ---> Number
	0 + string ---> Number

Example:

	see number("5") + 5 + nl 	# print 10
	see 0 + "10" + 2		# print 12

String() Function

edit

We can convert numbers to strings using the String() function or the + operator.

Syntax:

	String(number) ---> String
	"" + number ---> String

Example:

	see string(5) + 5 + nl 		# print 55
	see "" + 10 + 2			# print 102


Ascii() Function

edit

We can get the ASCII code for a letter using the Ascii() function

Syntax:

	Ascii(character) ---> ASCII Code

Example:

	See ascii("m") + nl + 	# print 109
	    ascii("M") 		# print 77

Char() Function

edit

We can convert the ASCII code to character using the Char() function.

Syntax:

	Char(ASCII Code) ---> character

Example:

	See char(109) + nl + 	# print m
	    char(77) 		# print M


Hex() Function

edit

We can convert decimal to hexadecimal using the Hex() function.

Syntax:

	Hex(decimal) ---> hexadecimal

Example:

	See hex(10) + nl + 	# print a
	    hex(200)		# print c8

Dec() Function

edit

We can convert hexadecimal to decimal using the Dec() function

Syntax:

	Dec(hexadecimal) ---> decimal

Example:

	See dec("a") + nl + 	# print 10
	    dec("c8")		# print 200

Str2hex() Function

edit

We can convert string characters to hexadecimal characters using the Str2hex() function.

Syntax:

	Str2hex(string) ---> hexadecimal string

Example:

	See str2hex("hello")  	# print 68656c6c6f


Hex2str() Function

edit

We can convert hexadecimal characters to string using the Hex2str() function

Syntax:

	Hex2Str(Hexadecimal string) ---> string

Example:

	See hex2str("68656c6c6f")  	# print hello



Lessons/Mathematical Functions

Mathematical Functions

edit

In this chapter we are going to learn about the mathematical functions

List of functions

edit

The Ring programming language comes with the next mathematical functions

===============		=============================================================================
Function                Description
===============		=============================================================================
sin(x)                  Returns the sine of an angle of x radians
cos(x)                  Returns the cosine of an angle of x radians
tan(x)                  Returns the tangent of an angle of x radians
asin(x)                 Returns the principal value of the arc sine of x, expressed in radians
acos(x)                 Returns the principal value of the arc cosine of x, expressed in radians
atan(x)                 Returns the principal value of the arc tangent of x, expressed in radians
atan2(y,x)              Returns the principal arc tangent of y/x, in the interval [-pi,+pi] radians
sinh(x)                 Returns the hyperbolic sine of x radians
cosh(x)                 Returns the hyperbolic cosine of x radians
tanh(x)                 Returns the hyperbolic tangent of x radians
exp(x)                  Returns the value of e raised to the xth power
log(x)                  Returns the natural logarithm of x
log10(x)                Returns the common logarithm (base-10 logarithm) of x
ceil(x)                 Returns the smallest integer value greater than or equal to x	
floor(x)                Returns the largest integer value less than or equal to x
fabs(x)                 Returns the absolute value of x.
pow(x,y)                Returns x raised to the power of y 
sqrt(x)                 Returns the square root of x
random(x)               Returns a random number in the range [0,x]
unsigned(n,n,c)         Perform operation using unsigned numbers 
decimals(n)             Determine the decimals digits after the point in float/double numbers
=============== 	=============================================================================

Example

edit
	See "Mathematical Functions" + nl
	See "Sin(0) = " + sin(0) + nl
	See "Sin(90) radians = " + sin(90) + nl
	See "Sin(90) degree = " + sin(90*3.14/180) + nl

	See "Cos(0) = " + cos(0) + nl
	See "Cos(90) radians = " + cos(90) + nl
	See "Cos(90) degree = " + cos(90*3.14/180) + nl

	See "Tan(0) = " + tan(0) + nl
	See "Tan(90) radians = " + tan(90) + nl
	See "Tan(90) degree = " + tan(90*3.14/180) + nl

	See "asin(0) = " + asin(0) + nl
	See "acos(0) = " + acos(0) + nl
	See "atan(0) = " + atan(0) + nl
	See "atan2(1,1) = " + atan2(1,1) + nl

	See "sinh(0) = " + sinh(0) + nl
	See "sinh(1) = " + sinh(1) + nl
	See "cosh(0) = " + cosh(0) + nl
	See "cosh(1) = " + cosh(1) + nl
	See "tanh(0) = " + tanh(0) + nl
	See "tanh(1) = " + tanh(1) + nl

	See "exp(0) = " + exp(0) + nl
	See "exp(1) = " + exp(1) + nl
	See "log(1) = " + log(1) + nl
	See "log(2) = " + log(2) + nl
	See "log10(1) = " + log10(1) + nl
	See "log10(2) = " + log10(2) + nl
	See "log10(10) = " + log10(10) + nl

	See "Ceil(1.12) = " + Ceil(1.12) + nl
	See "Ceil(1.72) = " + Ceil(1.72) + nl

	See "Floor(1.12) = " + floor(1.12) + nl
	See "Floor(1.72) = " + floor(1.72) + nl

	See "fabs(1.12) = " + fabs(1.12) + nl
	See "fabs(1.72) = " + fabs(1.72) + nl

	See "pow(2,3) = " + pow(2,3) + nl

	see "sqrt(16) = " + sqrt(16) + nl


Program Output:

	Mathematical Functions
	Sin(0) = 0
	Sin(90) radians = 0.89
	Sin(90) degree = 1.00
	Cos(0) = 1
	Cos(90) radians = -0.45
	Cos(90) degree = 0.00
	Tan(0) = 0
	Tan(90) radians = -2.00
	Tan(90) degree = 1255.77
	asin(0) = 0
	acos(0) = 1.57
	atan(0) = 0
	atan2(1,1) = 0.79
	sinh(0) = 0
	sinh(1) = 1.18
	cosh(0) = 1
	cosh(1) = 1.54
	tanh(0) = 0
	tanh(1) = 0.76
	exp(0) = 1
	exp(1) = 2.72
	log(1) = 0
	log(2) = 0.69
	log10(1) = 0
	log10(2) = 0.30
	log10(10) = 1
	Ceil(1.12) = 2
	Ceil(1.72) = 2
	Floor(1.12) = 1
	Floor(1.72) = 1
	fabs(1.12) = 1.12
	fabs(1.72) = 1.72
	pow(2,3) = 8
	sqrt(16) = 4

Random() Function

edit

The Random() function generate a random number and we can set the maximum value (optional).

Syntax:

	Random(x) ---> Random number in the range [0,x]

Example:

	for x = 1 to 20
		see  "Random number : " + random() + nl +
		     "Random number Max (100) : " + random(100) + nl
	next

Program Output:

	Random number : 31881
	Random number Max (100) : 80
	Random number : 5573
	Random number Max (100) : 63
	Random number : 2231
	Random number Max (100) : 43
	Random number : 12946
	Random number Max (100) : 39
	Random number : 22934
	Random number Max (100) : 48
	Random number : 4690
	Random number Max (100) : 52
	Random number : 13196
	Random number Max (100) : 65
	Random number : 30390
	Random number Max (100) : 87
	Random number : 4327
	Random number Max (100) : 77
	Random number : 12456
	Random number Max (100) : 17
	Random number : 28438
	Random number Max (100) : 13
	Random number : 30503
	Random number Max (100) : 6
	Random number : 31769
	Random number Max (100) : 94
	Random number : 8274
	Random number Max (100) : 65
	Random number : 14390
	Random number Max (100) : 90
	Random number : 28866
	Random number Max (100) : 12
	Random number : 24558
	Random number Max (100) : 70
	Random number : 29981
	Random number Max (100) : 77
	Random number : 12847
	Random number Max (100) : 63
	Random number : 6632
	Random number Max (100) : 60

Unsigned() Function

edit

We can use unsigned numbers using the Unsigned() function.

Syntax:

	Unsigned(nNum1,nNum2,cOperator)	--> result of cOperator operation on nNum1,nNum2

Example:

	see oat_hash("hello") + nl

	# Jenkins hash function - https://en.wikipedia.org/wiki/Jenkins_hash_function
	func oat_hash cKey	
		h = 0
		for x in cKey
			h = unsigned(h,ascii(x),"+")
			h = unsigned(h,unsigned(h,10,"<<"),"+")
			r = unsigned(h,6,">>")
			h = unsigned(h, r,"^")
		next
		h = unsigned(h,unsigned(h,3,"<<"),"+")
		h = unsigned(h,unsigned(h,11,">>"),"^")
		h = unsigned(h,unsigned(h,15,"<<"),"+")
		return h

Output:

	3372029979.00

Decimals() Functions

edit

We can determine the decimals numbers count after the point in float/double numbers using the decimals() function.

Syntax:

	Decimals(nDecimalsCount)

Example:

	x = 1.1234567890123
	for d = 0 to 14
		decimals(d)
		see x + nl
	next


Output:

	1
	1.1
	1.12
	1.123
	1.1235
	1.12346
	1.123457
	1.1234568
	1.12345679
	1.123456789
	1.1234567890
	1.12345678901
	1.123456789012
	1.1234567890123
	1.12345678901230



Lessons/Files

Files

edit

In this chapter we are going to learn about files functions.

  • Read()
  • Write()
  • Dir()
  • Rename()
  • Remove()
  • fopen()
  • fclose()
  • fflush()
  • freopen()
  • tempfile()
  • tempname()
  • fseek()
  • ftell()
  • rewind()
  • fgetpos()
  • fsetpos()
  • clearerr()
  • feof()
  • ferror()
  • perror()
  • fgetc()
  • fgets()
  • fputc()
  • fputs()
  • ungetc()
  • fread()
  • fwrite()
  • fexists()



Read() Function

edit

We can read the file content using the Read() function

Syntax:

	Read(cFileName) ---> String contains the file content

Example:

	see read("myfile.txt")

The read function can read binary files too

Example:

	see read("myapp.exe")



Write() Function

edit

We can write string to file using the Write() function

The write function can write binary data to binary files.

Syntax:

	Write(cFileName,cString)	# write string cString to file cFileName

Example:

	# copy file
	cFile = read("ring.exe")
	write("ring2.exe",cFile)



Dir() Function

edit

We can get the folder contents (files & sub folders) using the Dir() function.

Syntax:

	Dir(cFolderPath) ---> List contains files & sub folders.

This function returns a list and each list item is a list of two items

  • File/sub folder name
  • Type (0 = File , 1 = Folder/Directory)

Example:

	see "Testing DIR() " + nl
	mylist = dir("C:\myfolder")
	for x in mylist
		if x[2] 
			see "Directory : " + x[1] + nl
		else
			see "File : " + x[1] + nl
		ok
	next
	see "Files count : " + len(mylist)


Rename() Function

edit

We can rename files using the Rename() function

Syntax:

	Rename(cOldFileName,cNewFileName)

Example:

	rename("file.txt","help.txt")

Remove() Function

edit

We can delete a file using the Remove() function


Syntax:

	Remove(cFileName)

Example:

	remove("test.txt")

Fopen() Function

edit

We can open a file using the Fopen() function

Syntax:

	Fopen(cFileName,cMode) ---> File Handle
=====	==========================================
Mode	Description
=====	==========================================
"r"     Reading (The file must exist)
"w"     Writing (create empty file / overwrite)
"a"     Appends (create file if it doesn't exist)
"r+"    update (reading/writing)
"w+"    Create empty file (reading/writing)
"a+"    reading & appending
=====	==========================================

Fclose() Function

edit

When we open a file using fopen() function, we can close it using the Fclose() function

Syntax:

	Fclose(file handle)

Fflush() Function

edit

We can flushes the output buffer of a stream using the Fflush() function

Syntax:

	Fflush(file handle)

Freopen() Function

edit

We can open another file using the same file handle and at the same file close the old file

Syntax:

	Freopen(cFileName,cMode,file handle) ---> file handle

Example:

	freopen("myprogoutput.txt","w+",stdout)
	see "welcome" + nl
	for x = 1 to 10
		see x + nl
	next

/* ** Read : https://en.wikipedia.org/wiki/Device_file#Device_files ** The next code is not portable, we can use iswindows() before ** using it and we can write special code for each operating system. */

freopen("CON","w",stdout) # For Microsoft Windows see "Done" + nl # print to stdout again

Output:

	# Output to stdout
	Done

# Output to file : myprogoutput.txt welcome 1 2 3 4 5 6 7 8 9 10

Tempfile() Function

edit

The function Tempfile() creates a temp. file (binary).

The file will be deleted automatically when the stream is closed

Syntax:

	TempFile() ---> file handle


Tempname() Function

edit

We can generate temp. file name using the Tempname() function

The generated name will be different from the name of any existing file

Syntax:

	Tempname() ---> generated file name as string

Fseek() Function

edit

We can set the file position of the stream using the Fseek() function

Syntax:

	Fseek(file handle, nOffset, nWhence) ---> zero if successful

The next table presents the nWhence values

=====	===============================
Value	Description
=====	===============================
0       Beginning of file
1       Current position
2       End of file
=====	===============================

Ftell() Function

edit

We can know the current file position of a stream using the Ftell() function

Syntax:

	Ftell(file handle) ---> file position as number

Rewind() Function

edit

We can set the file position to the beginning of the file using the Rewind() function

Syntax:

	
	Rewind(file handle)

Fgetpos() Function

edit

We can get handle to the current file position using the Fgetpos() function

Syntax:

	Fgetpos(file handle) ---> position handle

Fsetpos() Function

edit

We can set the current file position using the Fgetpos() function

Syntax:

	Fsetpos(file handle,position handle)

Clearerr() Function

edit

We can clear the EOF error and the error indicators of a stream using the clearerr() function

Syntax:

	Clearerr(file handle)

Feof() Function

edit

We can test the end-of-file indicator using the Feof() function

Syntax:

	Feof(file handle) ---> returns 1 if EOF and 0 if not

Ferror() Function

edit

We can test the error indicator of a given stream using the Ferror() function

Syntax:

	Ferror(file handle) ---> returns 1 if error and 0 if not

Perror() Function

edit

We can print error message to the stderr using the Perror() function

Syntax:

	Perror(cErrorMessage)

Fgetc() Function

edit

We can get the next character from the stream using the Fgetc() function

Syntax:

	Fgetc(file handle) ---> returns character or EOF


Fgets() Function

edit

We can read new line from the stream using the Fgets() function

Syntax:

	Fgets(file handle,nSize) ---> string

The function stop when nSize characters are read, new line character is read or EOF.

Fputc() Function

edit

We can write a character to the stream using the Fputc() function

Syntax:

	Fputc(file handle,cChar)

Fputs() Function

edit

We can write a string to the stream using the Fputs() function

Syntax:

	Fputs(file handle,cString)


Ungetc() Function

edit

We can push a character to the stream using the Ungetc() function

The character will be available for the next read

Syntax:

	Ungetc(file handle,character)


Fread() Function

edit

We can read data from a stream using the Fread() function

Syntax:

	Fread(file handle,nSize)

Fwrite() Function

edit

We can write data to a stream using the Fwrite() function

Syntax:

	Fwrite(file handle,cString)


Fexists() Function

edit

We can check if a file exists using the Fexists() function

Syntax:

	Fexists(cFileName) ---> returns 1 if the file exists

Example:

	see fexists("b:\mahmoud\apps\ring\ring.exe") + nl +
	    fexists("b:\mahmoud\apps\ring\ring2.exe") + nl

Output:

	1
	0

Example

edit

The next program test some of the file functions

	See "Testing file functions" + nl

	See "open file" + nl
	fp = fopen("tests\s65.ring","r")

	See "reopen" + nl
	fp = freopen("tests\s78.ring","r",fp)
	See "close file" + nl
	fclose(fp)

	see "temp file" + nl
	fp = tempfile()
	fclose(fp)

	see "temp name" + nl
	see tempname() + nl

	remove("tests\mytest1.txt")
	write("tests\test1.txt","hello")
	rename("tests\test1.txt","tests\mytest2.txt")

	see "print file" + nl
	fp = fopen("tests\file.ring","r")
	r = fgetc(fp)
	while isstring(r)
		see r
		r = fgetc(fp)
	end
	fclose(fp)

	see nl+"print line from the file" + nl
	fp = fopen("tests\file.ring","r")
	r = fgets(fp,100)
	see r
	fclose(fp)

	fp = fopen("tests\myfile.txt","rw+")
	fseek(fp,0,2) # goto end of file
	fputc(fp,"t")
	fputc(fp,"e")
	fputc(fp,"s")
	fputc(fp,"t")
	fputs(fp,"test2")
	fclose(fp)

	see "print file" + nl
	see read("tests\myfile.txt")

	fp = fopen("tests\myfile.txt","r")
	see "testing ungetc() " + nl
	for x = 1 to 3
		r = fgetc(fp)
		see r + nl
		ungetc(fp,r)
	next
	fclose(fp)

	see "testing fread() " + nl
	fp = fopen("ring.exe","r")
	r = fread(fp,100)
	see r + nl
	fclose(fp)

	see "testing fwrite() " + nl
	fp = fopen("tests\myfile.txt","wb")
	fwrite(fp,r)
	fclose(fp)



Lessons/System Functions

System Functions

edit

In this chapter we are going to learn about the system functions

  • System()
  • Get()
  • IsMSDOS()
  • IsWindows()
  • IsWindows64()
  • IsUnix()
  • IsMacOSX()
  • IsLinux()
  • IsFreeBSD()
  • IsAndroid()
  • Windowsnl()
  • Get Command Line Arguments
  • Get Active Source File Name

System() Function

edit

We can execute system commands using the system() function

Syntax:

	System(cCommand)

Example:

	System("myapp.exe") 	# Run myapp.exe
	System("ls")		# print list of files

Get() Function

edit

We can get environment variables using the Get() function

Syntax:

	Get(cVariable)

Example:

	see get("path")		# print system path information


IsMSDOS()

edit

We can check if the operating system is MSDOS or not using the IsMSDOS() function

Syntax:

	IsMSDOS() ---> Returns 1 if the operating system is MS-DOS, Returns 0 if it's not

IsWindows()

edit

We can check if the operating system is Windows or not using the IsWindows() function

Syntax:

	IsWindows() ---> Returns 1 if the operating system is Windows, Returns 0 if it's not


IsWindows64()

edit

We can check if the operating system is Windows 64bit or not using the IsWindows64() function

Syntax:

	IsWindows64() ---> Returns 1 if the operating system is Windows64, Returns 0 if it's not


IsUnix()

edit

We can check if the operating system is Unix or not using the IsUnix() function

Syntax:

	IsUnix() ---> Returns 1 if the operating system is Unix, Returns 0 if it's not


IsMacOSX()

edit

We can check if the operating system is Mac OS X or not using the IsMacOSX() function

Syntax:

	IsMacOSX() ---> Returns 1 if the operating system is Mac OS X, Returns 0 if it's not


IsLinux()

edit

We can check if the operating system is Linux or not using the IsLinux() function

Syntax:

	IsLinux() ---> Returns 1 if the operating system is Linux, Returns 0 if it's not


IsFreeBSD()

edit

We can check if the operating system is FreeBSD or not using the IsFreeBSD() function

Syntax:

	IsFreeBSD() ---> Returns 1 if the operating system is FreeBSD, Returns 0 if it's not


IsAndroid()

edit

We can check if the operating system is Android or not using the IsAndroid() function

Syntax:

	IsAndroid() ---> Returns 1 if the operating system is Android, Returns 0 if it's not

Example

edit
	see "IsMSDOS() --> " + ismsdos() + nl
	see "IsWindows() --> " + iswindows() + nl
	see "IsWindows64() --> " + iswindows64() + nl
	see "IsUnix() --> " + isunix() + nl
	see "IsMacOSX() --> " + ismacosx() + nl
	see "IsLinux() --> " + islinux() + nl
	see "IsFreeBSD() --> " + isfreebsd() + nl
	see "IsAndroid() --> " + isandroid() + nl

Output:

	IsMSDOS() --> 0
	IsWindows() --> 1
	IsWindows64() --> 0
	IsUnix() --> 0
	IsMacOSX() --> 0
	IsLinux() --> 0
	IsFreeBSD() --> 0
	IsAndroid() --> 0

Windowsnl()

edit

We can get the windows new line string using the Windowsnl() function.

Syntax:

	WindowsNL() ---> Returns a string contains CR+LF = CHAR(13) + CHAR(10)

Example:

	cStr = read("input.txt")

if iswindows() cStr = substr(cStr,windowsnl(),nl) ok

aList = str2list(cStr) # to do - list items processing using "for in" cStr = list2str(aList)

if iswindows() cStr = substr(cStr,nl,windowsnl()) ok

write("ouput.txt",cStr)

Get Command Line Arguments

edit

We can get the command line arguments passed to the ring script using the sysargv variable.

The sysargv variable is a list contains the command line parameters.

Example

	see copy("=",30) + nl
	see "Command Line Parameters" + nl
	see "Size : " + len(sysargv) + nl
	see sysargv
	see copy("=",30) + nl
	nStart = sysargv[3]
	nEnd = sysargv[4]
	for x = nStart to nEnd
		see x + nl
	next

Output

	b:\mahmoud\apps\ring>ring tests\syspara.ring 1 10
	==============================
	Command Line Parameters
	Size : 4
	ring
	tests\syspara.ring
	1
	10
	==============================
	1
	2
	3
	4
	5
	6
	7
	8
	9
	10

Get Active Source File Name

edit

We can get the active source file name (*.ring) using the filename() function

Syntax:

	filename() ---> String contains the active source file name.

Example:

	see "Active Source File Name : " + filename() + nl

Output:

	Active Source File Name : tests\filename.ring


Example:

	if sysargv[2] = filename()
		see "I'm the main program file!" + nl
		# we can run tests here!
	else
		see "I'm a sub file in a program" + nl
	ok



Lessons/Eval() and Debugging

Eval() and Debugging

edit

In this chapter we are going to learn about

  • Error Handling using Try/Catch/Done
  • Eval() function
  • Raise() function
  • Assert() function



Try/Catch/Done

edit

Syntax:

	Try
		Statements...
	Catch
		Statements...
	Done

The statements in the Try block will be executed, if any error happens then the statements in the catch block will be executed.

Inside the catch block we can use the variable cCatchError to get the error message

Example:

	Try
		see 5/0
	Catch
		see "Catch!" + nl + cCatchError
	Done

Output:

	Catch!
	Error (R1) : Cann't divide by zero !



Eval() Function

edit

We can execute code during the runtime from string using the Eval() function

Syntax:

	Eval(cCode)

Example:

	Eval("nOutput = 5+2*5 " )
	See "5+2*5 = " + nOutput + nl			 
	Eval("for x = 1 to 10 see x + nl next")		 
	Eval("func test see 'message from test!' ")	 
	test()

Output:

	5+2*5 = 15
	1
	2
	3
	4
	5
	6
	7
	8
	9
	10
	message from test!



Raise() Function

edit

We can raise an exception using the Raise() function

Syntax:

	Raise(cErrorMessage)

The function will display the error message then end the execution of the program.

We can use Try/Catch/Done to avoid exceptions generated by raise() function.

Example:

	nMode = 10

if nMode < 0 or nMode > 5 raise("Error : nMode not in the range 1:4") ok

Output:

	Line 4 Error : nMode not in the range 1:4
	In raise in file tests\raise.ring

Example:

	try 
		testmode(6)
	catch
		see "avoid raise!"
	done

	testmode(-1)

	func testmode nMode

		if nMode < 0 or nMode > 5
			raise("Error : nMode not in the range 1:4")
		ok

Output:

	avoid raise!
	Line 12 Error : nMode not in the range 1:4
	In raise In function testmode() in file tests\raise2.ring
	called from line 7  in file tests\raise2.ring

Assert() Function

edit

We can use the Assert() function to test conditions before executing the code

If the test fail the program will be terminated with an error message contains the assert condition.

Syntax:

	Assert( condition )

Example:

	x = 10
	assert( x = 10)
	assert( x = 100 )

Output:

	Line 3 Assertion Failed!
	In assert in file tests\assert.ring



Lessons/Demo Programs

Demo Programs

edit

In this chapter we will see simple demo programs

  • Language Shell
  • Main Menu



Language Shell

edit

We can create simple interactive programming environment using the next program

	while true 
		see nl + "code:> "
		give cCode 
		try
			eval(cCode) 
		catch
			see cCatchError
		done
	end

Output:

	code:> see "hello world"
	hello world
	code:> for x = 1 to 10 see x + nl next
	1
	2
	3
	4
	5
	6
	7
	8
	9
	10

	code:> func test see "Hello from test" + nl

	code:> test()
	Hello from test

	code:> bye
edit

Example:

	# Demo Program

	while true

		see "

		Main Menu
		===========
		[1] Say Hello
		[2] Sum two numbers
		[3] Stars
		[4] Fact
		[5] Exit

		" give nMenu see nl

		# we can use Switch-ON-Other-OFF instead of IF-BUT-ELSE-OK

		if nMenu = 1 sayhello() 
		but nMenu = 2 Sum()
		but nMenu = 3 Stars()
		but nMenu = 4 
			see "Enter Number : " give x
			see "Output : " 

			Try	
				see Fact(number(x))
			Catch
				see "Error in parameters!" + nl
			Done

		but nMenu = "5" return 
		else see "bad option" + nl
		ok

	end

	func sayhello
		see "Enter your name ? " give fname
		see "Hello " + fname + nl

	func sum
		see "number 1 : " give num1 see "number 2 : " give num2
		see "Sum : " see 0 + num1 + num2

	func stars
		for x = 1 to 10
			see space(8)
			for y = 1 to x see "*" next see nl
		next

	func fact x if x = 1 return 1 else return x * fact(x-1) ok

	func space x y = "" for t=1 to x y += " " next return y

Output:

	        Main Menu

	        [1] Say Hello
        	[2] Sum two numbers
	        [3] Stars
        	[4] Fact
	        [5] Exit

	        1

	Enter your name ? Mahmoud Fayed
	Hello Mahmoud Fayed


	        Main Menu
        	===========
	        [1] Say Hello
        	[2] Sum two numbers
	        [3] Stars
        	[4] Fact
	        [5] Exit

	        2

	number 1 : 3
	number 2 : 4
	Sum : 7

	        Main Menu
        	===========
	        [1] Say Hello
        	[2] Sum two numbers
	        [3] Stars
        	[4] Fact
	        [5] Exit

	        3

	        *
        	**
	        ***
        	****
	        *****
        	******
	        *******
	        ********
        	*********
	        **********


	        Main Menu
        	===========
	        [1] Say Hello
	        [2] Sum two numbers
        	[3] Stars
	        [4] Fact
	        [5] Exit

	        4

	Enter Number : 5
	Output : 120

	        Main Menu
        	===========
	        [1] Say Hello
        	[2] Sum two numbers
	        [3] Stars
        	[4] Fact
	        [5] Exit

	        5



Lessons/ODBC Functions

ODBC Functions

edit

This chapter contains the ODBC functions provided by the Ring programming language. Before using the functions load the odbclib.ring library:

	load "odbclib.ring"
  • odbc_init()
  • odbc_drivers()
  • odbc_datasources()
  • odbc_close()
  • odbc_connect()
  • odbc_disconnect()
  • odbc_execute()
  • odbc_colcount()
  • odbc_fetch()
  • odbc_getdata()
  • odbc_tables()
  • odbc_columns()
  • odbc_autocommit()
  • odbc_commit()
  • odbc_rollback()

odbc_init() Function

edit

We can create ODBC Handle using the odbc_init() function

Syntax:

	odbc_init() ---> ODBC Handle

odbc_drivers() Function

edit

We can get a list of ODBC drivers using the odbc_drivers() function

Syntax:

	odbc_drivers(ODBC Handle) ---> List of Drivers

odbc_datasources() Function

edit

We can get a list of ODBC data sources using the odbc_datasources() function

Syntax:

	odbc_datasources(ODBC Handle) ---> List of Data sources

odbc_close() Function

edit

After the end of using ODBC functions we can free resources using ODBC_Close() function

Syntax:

	odbc_close(ODBC Handle)
edit

The next example print a list of ODBC drivers.

	See "ODBC test 1" + nl
	oODBC = odbc_init()
	See "Drivers " + nl
	see odbc_drivers(oODBC)
	odbc_close(oODBC)

Output:

	ODBC test 1
	Drivers
	Microsoft Access-Treiber (*.mdb) - SQLLevel=0
	Driver do Microsoft Paradox (*.db ) - SQLLevel=0
	Driver do Microsoft Excel(*.xls) - SQLLevel=0
	Microsoft Text Driver (*.txt; *.csv) - SQLLevel=0
	Driver da Microsoft para arquivos texto (*.txt; *.csv) - SQLLevel=0
	Microsoft dBase-Treiber (*.dbf) - SQLLevel=0
	SQL Server - CPTimeout=60
	Microsoft Excel Driver (*.xls) - SQLLevel=0
	Driver do Microsoft dBase (*.dbf) - SQLLevel=0
	Microsoft Paradox-Treiber (*.db ) - SQLLevel=0
	Microsoft ODBC for Oracle - CPTimeout=120
	Microsoft Text-Treiber (*.txt; *.csv) - SQLLevel=0
	Microsoft Excel-Treiber (*.xls) - SQLLevel=0
	Microsoft Access Driver (*.mdb) - SQLLevel=0
	Driver do Microsoft Access (*.mdb) - SQLLevel=0
	Microsoft Paradox Driver (*.db ) - SQLLevel=0
	Microsoft dBase Driver (*.dbf) - SQLLevel=0
	Microsoft Access Driver (*.mdb, *.accdb) - UsageCount=3
	Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb) - UsageCount=3
	Microsoft Access Text Driver (*.txt, *.csv) - UsageCount=3
	SQL Server Native Client 10.0 - UsageCount=1
	SQL Server Native Client 11.0 - UsageCount=1
	Microsoft Access dBASE Driver (*.dbf, *.ndx, *.mdx) - UsageCount=3
	Microsoft Access Paradox Driver (*.db) - UsageCount=3
	MySQL ODBC 5.3 ANSI Driver - UsageCount=1
	MySQL ODBC 5.3 Unicode Driver - UsageCount=1
	ODBC Driver 11 for SQL Server - UsageCount=1
	Lianja ODBC Driver - CPTimeout=60
	Microsoft Visual FoxPro Driver - UsageCount=1
	Microsoft Visual FoxPro-Treiber - UsageCount=1
	Driver para o Microsoft Visual FoxPro - UsageCount=1
	Microsoft FoxPro VFP Driver (*.dbf) - UsageCount=1
edit

The next example print a list of ODBC data sources.

	See "ODBC test 2" + nl
	pODBC = odbc_init()
	See "Data Sources " + nl
	see odbc_datasources(pODBC)
	odbc_close(pODBC)

Output:

	ODBC test 2
	Data Sources
	Excel Files - Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)
	MS Access Database - Microsoft Access Driver (*.mdb, *.accdb)
	Customer - Microsoft Access Driver (*.mdb)
	IdCardData - Microsoft Access Driver (*.mdb)
	MyProjectData2 - Microsoft Access Driver (*.mdb)
	MyData - Microsoft Access Driver (*.mdb)
	MonprojetData - Microsoft Access Driver (*.mdb)
	dBASE Files - Microsoft Access dBASE Driver (*.dbf, *.ndx, *.mdx)
	myvfpdata - Microsoft Visual FoxPro Driver
	FACTORYDATA - Microsoft Access Driver (*.mdb)
	TRAININGSYSDATA - Microsoft Access Driver (*.mdb)
	RVCSYSDATASQLDB - SQL Server Native Client 11.0
	PWCTRVCDATA - Microsoft Access Driver (*.mdb)
	MyCompany - Microsoft Access Driver (*.mdb)
	HCS - Microsoft Access Driver (*.mdb)
	HCS2 - Microsoft Access Driver (*.mdb, *.accdb)
	MyProjectData - Microsoft Access Driver (*.mdb)
	Xtreme Sample Database 2008 - Microsoft Access Driver (*.mdb)
	Lianja_Southwind - Lianja ODBC Driver
	Visual FoxPro Database - Microsoft Visual FoxPro Driver
	Visual FoxPro Tables - Microsoft Visual FoxPro Driver

odbc_connect() Function

edit

We can connect to the database using the odbc_connect() function.

Syntax:

	odbc_connect(ODBC Handle, cConnectionString)

odbc_disconnect() Function

edit

We can close the connection to the database using the odbc_disconnect() function.

Syntax:

	odbc_disconnect(ODBC Handle)

Open and Close Connection

edit

The next example connect to the database then close the connection

	See "ODBC test 3" + nl
	pODBC = odbc_init()
	See "Connect to database" + nl
	see odbc_connect(pODBC,"DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl
	See "disconnect" + nl
	odbc_disconnect(pODBC)
	See "Close database..." + nl
	odbc_close(pODBC)

Output:

	ODBC test 3
	Connect to database
	1
	disconnect
	Close database...

odbc_execute() Function

edit

We can execute SQL Statements on the database using the odbc_execute() function.

Syntax:

	odbc_execute(ODBC Handle, cSQLStatement)


odbc_colcount() Function

edit

We can get columns count in the query result using the odbc_colcount() function.

Syntax:

	odbc_colcount(ODBC Handle) ---> Columns Count as Number

odbc_fetch() Function

edit

We can fetch a row from the query result using the odbc_fetch() function.

Syntax:

	odbc_fetch(ODBC Handle)

odbc_getdata() Function

edit

We can get column value from the fetched row using the odbc_getdata() function.

Syntax:

	odbc_getdata(ODBC Handle, nColumnNumber) ---> Column Value

Execute Query and Print Result

edit

The next example execute query then print the query result.

	See "ODBC test 4" + nl
	pODBC = odbc_init()
	See "Connect to database" + nl
	see odbc_connect(pODBC,"DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl
	See "Select data" + nl
	see odbc_execute(pODBC,"select * from person") + nl
	nMax = odbc_colcount(pODBC)
	See "Columns Count : " + nMax + nl
	while odbc_fetch(pODBC)
		See "Row data:" + nl
		for x = 1 to nMax
			see odbc_getdata(pODBC,x) + " - "
		next
	end
	See "Close database..." + nl
	odbc_disconnect(pODBC)
	odbc_close(pODBC)

odbc_tables() Function

edit

We can get a list of tables inside the database using the odbc_tables() function.

We can access the result of this function as we get any query result.

Syntax:

	odbc_tables(ODBC Handle)

Example:

	See "ODBC test - Get Database Tables" + nl
	pODBC = odbc_init()
	See "Connect to database" + nl
	odbc_connect(pODBC,"DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl
	See "Select data" + nl
	odbc_tables(pODBC) + nl
	nMax = odbc_colcount(pODBC)
	See "Columns Count : " + nMax + nl
	while odbc_fetch(pODBC)
		for x = 1 to nMax
			see odbc_getdata(pODBC,x) 
			if x != nMax see " - " ok
		next
		See nl
	end
	See "Close database..." 
	odbc_disconnect(pODBC)
	odbc_close(pODBC)

Output:

	ODBC test - Get Database Tables
	Connect to database
	Select data
	Columns Count : 5
	.\test - NULL - Customer - TABLE - NULL
	.\test - NULL - employee - TABLE - NULL
	.\test - NULL - person - TABLE - NULL
	.\test - NULL - tel - TABLE - NULL
	Close database...


odbc_columns() Function

edit

We can get a list of columns inside the table using the odbc_columns() function.

Syntax:

	odbc_columns(ODBC Handle, cTableName)

Example:

	See "ODBC test - Get Table Columns" + nl
	pODBC = odbc_init()
	See "Connect to database" + nl
	odbc_connect(pODBC,"DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl
	See "Get Columns inside the Person Table" + nl
	odbc_columns(pODBC,"person") + nl
	while odbc_fetch(pODBC)
		see odbc_getdata(pODBC,4) + nl
	end
	See "Close database..." + nl
	odbc_disconnect(pODBC)
	odbc_close(pODBC)

Output:

	ODBC test - Get Table Columns
	Connect to database
	Get Columns inside the Person Table
	FIRST
	LAST
	STREET
	CITY
	STATE
	ZIP
	HIREDATE
	MARRIED
	AGE
	SALARY
	NOTES
	Close database...

odbc_autocommit() Function

edit

We can enable or disable the auto commit feature using the odbc_autocommit() function.

Syntax:

	odbc_autocommit(ODBC Handle, lStatus)   # lStatus can be True or False


odbc_commit() Function

edit

We can commit updates to the database using the odbc_commit() function.

Syntax:

	odbc_commit(ODBC Handle)

odbc_rollback() Function

edit

We can rollback updates to the database using the odbc_rollback() function.

Syntax:

	odbc_rollback(ODBC Handle)

Transactions and Using Commit and Rollback

edit

Example:

	See "ODBC Test - Transactions and using Commit and Rollback" + nl
	pODBC = odbc_init()
	See "Connect to database" + nl
	see odbc_connect(pODBC,"DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl
	see "insert data..." + nl
	odbc_autocommit(pODBC,0)
	for x = 1 to 10000
		odbc_execute(pODBC,"insert into tel values (" + x + ",'mahmoud')")
	next
	for x = 10001 to 15000
		odbc_execute(pODBC,"insert into tel values (" + x + ",'samir')")
	next
	odbc_commit(pODBC)

for x = 15001 to 20000 odbc_execute(pODBC,"insert into tel values (" + x + ",'fayed')") next

ODBC_ROLLBACK(pODBC) odbc_execute(pODBC,"insert into tel values (" + x + ",'fayed')") odbc_commit(pODBC)

See "Close database..." + nl odbc_disconnect(pODBC) odbc_close(pODBC)

Output:

	ODBC Test - Transactions and using Commit and Rollback
	Connect to database
	1
	insert data...
	Close database...

Save and Restore images

edit

The next example save an image inside the database

	See "ODBC test - Save image in the database" + nl
	pODBC = odbc_init()
	See "Connect to database" + nl
	see odbc_connect(pODBC,"DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl
	see "Read Image File..." + nl
	cFile = str2hex(read("tests\mahmoud.jpg"))
	see "size " + len(CFile)+nl
	see "Save image in the database..." + nl
	stmt = "insert into tel values (20000,'mahmoud','" + cFile + "');"
	odbc_execute(pODBC,stmt)
	See "Close database..." + nl
	odbc_disconnect(pODBC)
	odbc_close(pODBC)

The next example restore the image from the database

	See "ODBC Test - Restore image from the database" + nl
	pODBC = odbc_init()
	See "Connect to database" + nl
	see odbc_connect(pODBC,"DBQ=test.mdb;Driver={Microsoft Access Driver (*.mdb)}") + nl
	See "Select data" + nl
	see odbc_execute(pODBC,"select * from tel") + nl
	nMax = odbc_colcount(pODBC)
	See "Columns Count : " + nMax + nl
	while odbc_fetch(pODBC)
		See "Write image file" + nl
		write("tests\great.jpg",hex2str( odbc_getdata(pODBC,3) ) )
	end
	See "Close database..." + nl
	odbc_disconnect(pODBC)
	odbc_close(pODBC)



Lessons/MySQL Functions

MySQL Functions

edit

In this chapter we are going to learn about the MySQL functions provided by the Ring programming language. Before using the functions load the mysqllib.ring library:

	load "mysqllib.ring"
  • MySQL_Info()
  • MySQL_Init()
  • MySQL_Error()
  • MySQL_Connect()
  • MySQL_Close()
  • MySQL_Query()
  • MySQL_Insert_ID()
  • MySQL_Result()
  • MySQL_Next_Result()
  • MySQL_Columns()
  • MySQL_Result2()
  • MySQL_Escape_String()
  • MySQL_AutoCommit()
  • MySQL_Commit()
  • MySQL_Rollback()

MySQL_Info() Function

edit

We can get the MySQL Client version using the MySQL_Info() function.

Syntax:

	MySQL_Info() ---> string contains the MySQL Client version

Example:

	see "MySQL Client Version : " + mysql_info()

Output:

	MySQL Client Version : 6.1.5

MySQL_Init() Function

edit

We can start using MySQL Client through the MySQL_Init() function.

Syntax:

	MySQL_Init() ---> MySQL Handle

MySQL_Error() Function

edit

We can get the error message from the MySQL Client using the MySQL_Error() function.

Syntax:

	MySQL_Error(MySQL Handle) ---> Error message as string

MySQL_Connect() Function

edit

We can connect to the MySQL database server using the MySQL_Connect() function.

Syntax:

	MySQL_Connect(MySQL Handle, cServer, cUserName, cPassword) ---> lStatus

MySQL_Close() Function

edit

We can close the connection to the MySQL database using the MySQL_Close() function

Syntax:

	MySQL_Close(MySQL Handle)

MySQL_Query() Function

edit

We can execute SQL queries using the MySQL_Query() function

Syntax:

	
	MySQL_Query(MySQL Handle, cSQLQuery)

Create Database

edit

The next example connect to MySQL Server then create new database.

	See "MySQL Test - Create Database" + nl
	con = mysql_init()

	See "Connect" + nl
	if mysql_connect(con,"localhost","root","root") = 0
		see "Cann't connect" + nl
		see "Error : " + mysql_error(con) + nl
		mysql_close(con)
		bye
	ok

	See "Create Database..." + nl
	mysql_query(con,"CREATE DATABASE mahdb")

	See "Close Connection" + nl
	mysql_close(con)

Output:

	MySQL Test - Create Database
	Connect
	Create Database...
	Close Connection

Create Table and Insert Data

edit

The next example create new table and insert records

	func main
		see "Create Table and Insert Records" + nl
		con = mysql_init()

		see "Connect" + nl
		if mysql_connect(con, "localhost", "root", "root","mahdb") = 0 
			system_error(con) 
		ok

		see "Drop table" + nl
		if mysql_query(con, "DROP TABLE IF EXISTS Employee")  system_error(con) ok
  
		see "Create table" + nl
		if mysql_query(con, "CREATE TABLE Employee(Id INT, Name TEXT, Salary INT)") 
		   system_error(con) ok
 
 		see "Insert data" + nl 
		if mysql_query(con, "INSERT INTO Employee VALUES(1,'Mahmoud',15000)") 
		   system_error(con) ok
  
		if mysql_query(con, "INSERT INTO Employee VALUES(2,'Samir',16000)") 
		   system_error(con) ok

		if mysql_query(con, "INSERT INTO Employee VALUES(3,'Fayed',17000)")  
		   system_error(con) ok

		see "Close connection" + nl
		mysql_close(con) 

	func system_error con
		see mysql_error(con)  mysql_close(con)  bye

Output:

	Create Table and Insert Records
	Connect
	Drop table
	Create table
	Insert data
	Close connection

MySQL_Insert_ID() Function

edit

We can get the inserted row id using the MySQL_Insert_ID() function

Syntax:

	MySQL_Insert_ID() ---> Inserted row id as number

Example:

	con = mysql_init()
	see "connect to database" + nl
	mysql_connect(con,"localhost","root","root","mahdb")
	see "drop table" + nl
	mysql_query(con, "DROP TABLE IF EXISTS Customers")
	see "create table" + nl
	mysql_query(con, "CREATE TABLE Customers(Id INT PRIMARY KEY AUTO_INCREMENT, Name TEXT)")
	see "insert record" + nl
	mysql_query(con, "INSERT INTO Customers(Name) VALUES('Mahmoud')")
	see "insert record" + nl
	mysql_query(con, "INSERT INTO Customers(Name) VALUES('Samir')")
	see "insert record" + nl
	mysql_query(con, "INSERT INTO Customers(Name) VALUES('Fayed')")
	see "insert record" + nl
	mysql_query(con, "INSERT INTO Customers(Name) VALUES('Test 2015')")

see "inserted row id : " + mysql_insert_id(con) + nl see "close database" + nl mysql_close(con)

Output:

	connect to database
	drop table
	create table
	insert record
	insert record
	insert record
	insert record
	inserted row id : 4
	close database

MySQL_Result() Function

edit

We can get the query result (data without column names) using the MySQL_Result() function.

Syntax:

	MySQL_Result(MySQL Handle) ---> List contains the query result

MySQL_Next_Result() Function

edit

We can move to the next query result using the MySQL_Next_Result() function. We use this function when we have multiple SQL statements in the same query.

Syntax:

	MySQL_Next_Result(MySQL Handle)
edit

The next example execute a query on the database then print the result.

	con = mysql_init()
	see "Connect to database" + nl
	mysql_connect(con, "localhost", "root", "root","mahdb")
	see "Execute Query" + nl
	mysql_query(con, "SELECT Name FROM Employee WHERE Id=1;"+
			 "SELECT Name FROM Employee WHERE Id=3")
	see "Print Result" + nl 
	see mysql_result(con)
	mysql_next_result(con)
	see mysql_result(con)
	see "close database" + nl
	mysql_close(con)

Output:

	Connect to database
	Execute Query
	Print Result
	Mahmoud
	Fayed
	close database

MySQL_Columns() Function

edit

We can get a list of columns names using the MySQL_Columns() function.

Syntax:

	MySQL_Columns(MySQL Handle) ---> List contains columns information

Example:

	con = mysql_init()
	see "Connect to database" + nl
	mysql_connect(con, "localhost", "root", "root","mahdb")
	see "Execute Query" + nl
	mysql_query(con, "SELECT * FROM Employee")
	see "Result" + nl 
	see mysql_columns(con)
	see "Close database" + nl
	mysql_close(con)

Output:

	Connect to database
	Execute Query
	Result
	Id
	11
	3
	32768
	Name
	65535
	252
	16
	Salary
	11
	3
	32768
	Close database

MySQL_Result2() Function

edit

Instead of using MySQL_Result() to get the result data without columns names, we can use the MySQL_Result2() to get all of the column names then the query result in one list.

Syntax:

	MySQL_Result2(MySQL Handle) ---> List (query result starts with columns names)

Example:

	con = mysql_init()
	see "Connect to database" + nl
	mysql_connect(con, "localhost", "root", "root","mahdb")
	see "Execute Query" + nl
	mysql_query(con, "SELECT * FROM Employee")
	see "Print Result" + nl 
	see mysql_result2(con)
	see "Close database" + nl
	mysql_close(con)

Output:

	Connect to database
	Execute Query
	Print Result
	Id
	Name
	Salary
	1
	Mahmoud
	15000
	2
	Samir
	16000
	3
	Fayed
	17000
	Close database


MySQL_Escape_String() Function

edit

We can store binary data and special characters in the database after processing using MySQL_Escape_String() function

Syntax:

	MySQL_Escape_String(MySQL Handle, cString) ---> String after processing

Save Image inside the database

edit

Example:

	See "Read file" + nl
	cFile = read("tests\mahmoud.jpg")
	con = mysql_init()
	See "Connect to database..." + nl
	mysql_connect(con, "localhost", "root", "root","mahdb")
	See "Escape string..." + nl
	cFile = mysql_escape_string(con,cFile)
	stmt = "INSERT INTO photo(id, data) VALUES(1, '" + cFile + "')"
	See "Insert data..." + nl
	mysql_query(con,stmt)
	See "Close database..." + nl
	mysql_close(con)

Output:

	Read file
	Connect to database...
	Escape string...
	Insert data...
	Close database...

Restore Image From The Database

edit

Example:

	con = mysql_init()
	See "Connect to database..." + nl
	mysql_connect(con, "localhost", "root", "root","mahdb")
	See "Read data from database..." + nl
	mysql_query(con,"SELECT data FROM photo WHERE id=1")
	See "Write new file" + nl
	result = mysql_result(con)
	write("tests\mahmoud2.jpg",result[1][1])
	See "Close database..." + nl
	mysql_close(con)

Output:

	Connect to database...
	Read data from database...
	Write new file
	Close database...


MySQL_AutoCommit() Function

edit

We can enable or disable the auto commit feature using the MySQL_AutoCommit() function.

Syntax:

	MySQL_AutoCommit(MySQL Handle, lStatus)  # lstatus can be True/False

MySQL_Commit() Function

edit

We can commit updates to the database using the MySQL_Commit() function.

Syntax:

	MySQL_Commit(MySQL Handle)

MySQL_Rollback() Function

edit

We can rollback updates to the database using the MySQL_Rollback() function.

Syntax:

	MySQL_Rollback(MySQL Handle)

Transaction Example

edit

The next example presents the usage of MySQL_Autocommit(), MySQL_Commit() & MySQL_RollBack() functions.

Example:

	func main
	
		con = mysql_init()

		see "Connect" + nl
		if mysql_connect(con, "localhost", "root", "root","mahdb") = 0 
			system_error(con) ok

		see "Drop table" + nl
		if mysql_query(con, "DROP TABLE IF EXISTS Employee2") 
			system_error(con) ok
  
		see "Create table" + nl
		if mysql_query(con, "CREATE TABLE Employee2(Id INT, Name TEXT, Salary INT)")
			system_error(con) ok
 
 		see "Insert data" + nl 
		if mysql_query(con, "INSERT INTO Employee2 VALUES(1,'Mahmoud',15000)") 
			system_error(con) ok
  
		if mysql_query(con, "INSERT INTO Employee2 VALUES(2,'Samir',16000)")
			system_error(con) ok

		if mysql_query(con, "INSERT INTO Employee2 VALUES(3,'Fayed',17000)") 
			system_error(con) ok

		mysql_autocommit(con,False)
		mysql_query(con, "INSERT INTO Employee2 VALUES(4,'Ahmed',5000)")
		mysql_query(con, "INSERT INTO Employee2 VALUES(5,'Ibrahim',50000)")
		mysql_query(con, "INSERT INTO Employee2 VALUES(6,'Mohammed',50000)")
		See "Save transaction (y/n) " give nChoice
		if upper(nChoice) = "Y"
			mysql_commit(con)
		else
			mysql_rollback(con)
		ok

		see "Close connection" + nl
		mysql_close(con) 

	func system_error con

		see mysql_error(con)
		mysql_close(con)
		bye

Output:

	Connect
	Drop table
	Create table
	Insert data
	Save transaction (y/n) y
	Close connection



Lessons/Security and Internet Functions

Security and Internet Functions

edit

This chapter contains the security and internet functions provided by the Ring programming language for Hashing, Encryption & Decryption. Before using the functions load the openssllib.ring library:

	load "openssllib.ring"
  • MD5()
  • SHA1()
  • SHA256()
  • SHA512()
  • SHA384()
  • SHA224()
  • Encrypt()
  • Decrypt()
  • Randbytes()

Before using the functions load the internetlib.ring library:

	load "internetlib.ring"
  • Download()
  • SendEmail()

MD5() Function

edit

We can calculate the MD5 hash using the MD5() Function

Syntax:

	MD5(cString) ---> String contains the MD5 hash of the string cString

Example:

	see "md5('happy') = " + md5("happy") + nl +
	    "md5('Hello') = " + md5("Hello") + nl

Output:

	md5('happy') = 56ab24c15b72a457069c5ea42fcfc640
	md5('Hello') = 8b1a9953c4611296a827abf8c47804d7

SHA1() Function

edit

We can calculate the SHA1 hash using the SHA1() Function

Syntax:

	SHA1(cString) ---> String contains the SHA1 hash of the string cString

Example:

	see "sha1('hello') : " + sha1("hello") + nl +
	    "sha1('apple') : " + sha1("apple") + nl

Output:

	sha1('hello') : aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
	sha1('apple') : d0be2dc421be4fcd0172e5afceea3970e2f3d940

SHA256() Function

edit

We can calculate the SHA256 hash using the SHA256() Function

Syntax:

	SHA256(cString) ---> String contains the SHA256 hash of the string cString


Example:

	see "sha256('hello') : " + sha256("hello") + nl +
	    "sha256('apple') : " + sha256("apple") + nl

Output:

	sha256('hello') : 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
	sha256('apple') : 3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b

SHA512() Function

edit

We can calculate the SHA512 hash using the SHA512() Function

Syntax:

	SHA512(cString) ---> String contains the SHA512 hash of the string cString

Example:

	see "sha512('hello') : " + sha512("hello") + nl +
	    "sha512('apple') : " + sha512("apple") + nl +
	    "sha512('hello world') : " + sha512("hello world") + nl

Output:

	sha512('hello') : 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673c
	a72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
	sha512('apple') : 844d8779103b94c18f4aa4cc0c3b4474058580a991fba85d3ca698a0bc9e52
	c5940feb7a65a3a290e17e6b23ee943ecc4f73e7490327245b4fe5d5efb590feb2
	sha512('hello world') : 309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca8
	6d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f

SHA384() Function

edit

We can calculate the SHA384 hash using the SHA384() Function

Syntax:

	SHA384(cString) ---> String contains the SHA384 hash of the string cString

Example:

	see "sha384('hello') : " + sha384("hello") + nl +
	    "sha384('apple') : " + sha384("apple") + nl +
	    "sha384('hello world') : " + sha384("hello world") + nl

Output:

	sha384('hello') : 59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa
	90125a3c79f90397bdf5f6a13de828684f
	sha384('apple') : 3d8786fcb588c93348756c6429717dc6c374a14f7029362281a3b21dc10250
	ddf0d0578052749822eb08bc0dc1e68b0f
	sha384('hello world') : fdbd8e75a67f29f701a4e040385e2e23986303ea10239211af907fcb
	b83578b3e417cb71ce646efd0819dd8c088de1bd

SHA224() Function

edit

We can calculate the SHA224 hash using the SHA224() Function

Syntax:

	SHA224(cString) ---> String contains the SHA224 hash of the string cString

Example:

	see "sha224('hello') : " + sha224("hello") + nl + 
	    "sha224('apple') : " + sha224("apple") + nl +
	    "sha224('hello world') : " + sha224("hello world") + nl

Output:

	sha224('hello') : ea09ae9cc6768c50fcee903ed054556e5bfc8347907f12598aa24193
	sha224('apple') : b7bbfdf1a1012999b3c466fdeb906a629caa5e3e022428d1eb702281
	sha224('hello world') : 2f05477fc24bb4faefd86517156dafdecec45b8ad3cf2522a563582b

Encrypt() Function

edit

We can use the Encrypt() function to encrypts the data using the Blowfish algorithm.

Syntax:

	Encrypt(cString, cKey, cIV) ---> Encrypted string

Decrypt() Function

edit

We can use the Decrypt() function to decrypt the data encrypted using the Encrypt() function.

Syntax:

	Decrypt(cCipher, cKey, cIV) ---> Decrypted string

Encryption and Decryption Example

edit

The next example demonstrates how to use the Encrypt() and Decrypt() functions.

These functions use the Blowfish algorithm.

	See "Enter a string : " give cStr
	list = 0:15  cKey=""    for x in list cKey += char(x) next
	list = 1:8   cIV = ""   for x in list cIV += char(x) next
	cStr = Encrypt(cStr,cKey,cIV) 
	See "Cipher Text    : " + cStr + nl +
	    "Plain Text     : " + Decrypt(cStr,cKey,cIV) + nl

File Hash

edit

The next example demonstrates how to calculate the hash functions for files

	cStr = read("myapp.exe")
	see "Size : " + len(cStr) + nl +
	    "md5 : " + md5(cStr) + nl +
	    "sha1 : " + sha1(cStr) + nl +
	    "sha256 : " + sha256(cStr) + nl +
	    "sha224 : " + sha224(cStr) + nl +
	    "sha384 : " + sha384(cStr) + nl +
	    "sha512 : " + sha512(cStr) + nl

Output:

	Size : 58079876
	md5 : 762eee15d8d2fd73b71ea52538b28667
	sha1 : 9212c0c7258bad89a62bd239e1358a9276a9d070
	sha256 : 7d6724e69b6c553da749ba31b6185dddc965129b64d9e9bf3de88f67df3b1cdc
	sha224 : 5a9c8a7d662bce4f880ba94f90a79362b672528b9efd5abc718c7a3d
	sha384 : 18e23f973abedbeb3981c423f12aeadecf96f9c6fb28aeabe3be4c484f8540afcc3861b
	b370ce2b59cf3c99c130b856b
	sha512 : da3d5e997d06f8b2a7a9964b77f7d82eedb76b245c611082c1639f83f51d83880bcd08f
	cd53dcab1167bdca0b82fec5071971ac17c76479d76985ced4ab0d18e

Randbytes() Function

edit

We can generate a string of pseudo-random bytes using the Randbytes() function.

Syntax:

	Randbytes(nSize) ---> String contains random bytes (bytes count = nSize)

Example:

	salt =  randbytes(32) 
	password = "SecretPassWord@$%123"
	see salt + nl
	see sha256("test" + salt) + nl

Download() Function

edit

Syntax:

	Download(cURL) ---> String contains the server response

Example:

	cStr= download("http://doublesvsoop.sourceforge.net/")
	see cStr
	write("download.txt",cStr)

SendEmail() Function

edit

Syntax:

	SendEmail(cSMTPServer,cEmail,cPassword,cSender,cReceiver,cCC,cTitle,cContent)

Example:

	See "Send email..." + nl
	sendemail("smtp://smtp.gmail.com:587",
		"email@gmail.com",
		"password",
		"email@gmail.com",
		"somebody@yahoo.com",
		"somebodyelse@yahoo.com",
		"Sending email from Ring",
		"Hello
		 How are you?
		 Are you fine?
		 Thank you!
		 Greetings,
		 Mahmoud")
	see "Done.." + nl



Lessons/Object Oriented Programming (OOP)

Object Oriented Programming (OOP)

edit

In this chapter we are going to learn how to use the Object-Oriented programming paradigm inside the Ring programming language.

We will learn about

  • Classes and Objects
  • Access Objects Using Braces
  • Composition
  • Setter and Getter
  • Private Attributes and Methods
  • Operator Overloading
  • Inheritance
  • Dynamic Attributes
  • Packages



Classes and Objects

edit

We can define new classes using the next syntax

Syntax:

	Class <Class Name> [From <Parent Class Name>]
		[Attributes]
		[Methods]
		[Private
                  [Attributes]
		  [Methods]
                ]

And we can create objects using the next syntax

Syntax:

	New <Object Name> [ (init method parameters) ] |
			  [ { access object data and methods } ]   ---> Object

Example:

	New point { x=10  y=20  z=30  print() }
	Class Point x y z func print see x + nl + y + nl + z + nl

.. note:: We can use { } to access object data and methods.

.. tip:: we can declare the class attributes directly after the class name.

Output:

	10
	20
	30

We can rewrite the same program in another style

	New point 			# create new object using the point class
	{ 				# access the new object attributes and methods
		x = 10 			# set the x attribute to 10
		y = 20 			# set the y attribute to 20
		z = 30 			# set the z attribute to 30
		print() 		# call the print method
	}				# end of object access


Class Point # define the Point class x y z # the class contains three attributes x, y & z func print # define the print method see x + nl + # print the x attribute y + nl + # print the y attribute z + nl # print the z attribute


Also we can write the same program in another way

	P1 = New Point
	P1.x = 10
	P1.y = 20
	P1.z = 30
	P1.Print()
	Class Point x y z func print see x + nl + y + nl + z + nl

.. note:: we can use the dot operator after the object name to access object members.

Also we can write the same program in another way

	new point { print() } 	
	Class Point
		x = 10  y = 20  z = 30
		func print see x + nl + y + nl + z + nl

.. note:: we can set the default values for the class attributes when we declare them.

Also we can write the same program in another way

	new point(10,20,30)
	Class Point
		x y z 
		func init p1,p2,p3 x=p1 y=p2 z=p3 print()
		func print see x + nl + y + nl + z + nl

.. note:: we can call the init method directly using () when we create new objects

Also we can write the same program in another way

	new point( [ :x = 10 , :y = 20 , :z = 30 ] )
	Class Point x y z
	      func init aPara x = aPara[:x] y = aPara[:y] z = aPara[:z] print()


.. tip:: using Hash for passing method parameters enable us to create optional

        parameters and change the order of parameters when adding them to the Hash.

Access Objects Using Braces

edit

We can access the object at any time using braces { }

Inside the braces we can use the object attributes and methods directly

This can be done when we create the object using the New keyword or at any time using the next syntax

	ObjectName { access object data and methods }

Example:

	See "Creating the Object" + nl
	o1 = new Point
	See "Using the Object" + nl
	o1 {
		x=5 	
		y=15
		z=25	
		print()
	}
	Class Point x y z func print see x + nl + y + nl + z

We can use braces to access objects when we call functions or methods

Example:

	o1 = new Point

	print( o1 { x=10 y=20 z=30 } )
	
	func print object
		see object.x + nl + 
		    object.y + nl + 
		    object.z 

	Class Point x y z

We can mix between using braces and the dot operator to access the object in the same expression.


Example:

	o1 = new Point

	O1 { x=10 y=20 z=30 }.print()
	
	Class Point x y z
		func print see x + nl + y + nl + z

Composition

edit

The object may contains other objects as attributes.

Using braces to access objects can be nested.

Example:

	R1 = New Rectangle 
	{

		Name = "Rectangle 1"

		P1 
		{
			X = 10
			Y = 20
		}

		P2 
		{
			X = 200
			Y = 300
		}	

	        Color = "Blue"

	}
	
	see "Name : " + R1.Name + nl +
	    "Color: " + R1.Color + nl +
	    "P1   : (" + R1.P1.X + "," + R1.P1.Y + ")" + nl + 
	    "P2   : (" + R1.P2.X + "," + R1.P2.Y + ")"  

	Class Rectangle
		name  color
		p1 = new Point
		p2 = new Point

	Class Point x y

Output:

	Name : Rectangle 1
	Color: Blue
	P1   : (10,20)
	P2   : (200,300)

Setter and Getter

edit

We can define methods to be used when we set and get object attributes.

Syntax:

	Class ClassName

		AttributeName
		...

		Func SetAttributeName
			...

		Func GetAttributeName
			...

Example:

	o1 = new person

	o1.name = "Mahmoud"  see o1.name + nl

	o1 { name = "Ahmed"  see name }

	Class Person

		name family = "Fayed"

		func setname value
			see "Message from SetName() Function!" + nl
			name = value + " " + family

		func getname
			see "Message from GetName() Function!" + nl
			return "Mr. " + name

Output:

	Message from SetName() Function!
	Message from GetName() Function!
	Mr. Mahmoud Fayed
	Message from SetName() Function!
	Message from GetName() Function!
	Mr. Ahmed Fayed

Private Attributes and Methods

edit

We can define private attributes and methods after the keyword private inside the class body

Example:

	o1 = new person {
		name = "Test"
		age = 20
		print()
		o1.printsalary()
	}

	try
		see o1.salary
	catch
		see cCatchError + nl
	done

	try
		o1.increasesalary(1000)
	catch
		see cCatchError + nl
	done

	Class Person

		name age 

		func print
			see "Name   : " + name + nl + 
			    "Age    : " + age + nl 

		func printsalary
		  	see "Salary : " + salary + nl 

		private

		salary = 15000

		func increasesalary x
			salary += x

Output:

	Name   : Test
	Age    : 20
	Salary : 15000
	Error (R27) : Using private attribute from outside the class : salary
	Error (R26) : Calling private method from outside the class : increasesalary

Operator Overloading

edit

We can add the operator method to our class to enable using operators with the class objects.

Syntax:

	Class ClassName

		...

		Func operator cOperator,Para

			...

The function operator takes two paramters, the first represent the operator and the second represent the second parameter after the operator.

Example:

	o1 = new point { x = 10 y = 10 print("P1    : ") }
	o2 = new point { x = 20 y = 40 print("P2    : ") }

	o3 = o1 + o2
	o3.print("P1+P2 : ")

	class point x y

		func operator cOperator,Para
			result = new point	
			switch cOperator
			on "+"
				result.x = x + Para.x
				result.y = y + Para.y
			on "-"
				result.x = x - Para.x
				result.y = y - Para.y
			off
			return result

		func print cPoint
			see cPoint + "X : " + x + " Y : " + y + nl

Output:

	P1    : X : 10 Y : 10
	P2    : X : 20 Y : 40
	P1+P2 : X : 30 Y : 50

Inheritance

edit

We can create class from another class in the class definition using the keyword from.

Syntax:

	Class <Class Name> [From <Parent Class Name>]

We can call a method in the parent class from the child class using the super object.

Syntax:

	func methodname
		...
		super.methodname()
		...

Example:

	Func main
		e1 = new Employee {
			Name = "test"
			age = 20
			job = "programmer"
			salary = 20000000
			print()
		}
	
	Class Human 
		Name Age
		func print
			see "Name : " + name + nl + "Age  : " + age + nl

	Class Employee from Human
		Job Salary
		func print
			super.print()
			see "Job  : " + job + nl + "Salary : " + salary + nl

Output:

	Name : test
	Age  : 20
	Job  : programmer
	Salary : 20000000

Dynamic Attributes

edit

We can write instructions after the class name to be executed when we create new objects

Example:

	o1 = new dynamicClass
	see o1.var5 + nl	# output 5

	Class DynamicClass
		for x = 1 to 10
			cStr = "var" + x + " = " + x
			eval(cStr)
		next

.. tip:: in the previous example var1, var2, ..., var10 will be defined as attributes.

.. tip:: The problem with the previous example is that x and cStr will be defined as attributes too!

.. note:: we can write class definitions inside a string then using eval() we can execute the string to define the classes

Packages

edit

We can create a package (a group of classes under a common name) using the next syntax

	package PackageName
		Class Class1
			...
		Class Class2
			...
		Class Class3
			...
		...

Example

	o1 = new System.output.console
	o1.print("Hello World")
	
	Package System.Output
		Class Console
			Func Print cText
				see cText + nl

.. note:: we can use the dot operator as part of the package name

Instead of typing the long name PackageName.ClassName we can use the import command

When we import a package, we can use any class inside this package directly.

Example

	import system.output
	o1 = new console {
		print("Hello World")
	}
	Package System.Output
		Class Console
			Func Print cText
				see cText + nl

Printing Objects

edit

We can print the object state (attributes and values) using the see command.

Example:

	see new point { x=10 y=20 z=30 }
	class point x y z

Output:

	x: 10.000000
	y: 20.000000
	z: 30.000000



Lessons/Declarative Programming using Nested Structures

Declarative Programming using Nested Structures

edit

In this chapter we are going to learn how to build declarative programming world using nested structures on the top of object oriented.

We will learn about

  • Creating Objects inside Lists
  • Composition and Returning Objects and Lists by Reference
  • Executing code after the end of object access
  • Declarative Programming on the top of Object-Oriented

Creating Objects inside Lists

edit

We can create objects inside lists during list definition. Also we can add objects to the list at any time using the Add() function or the + operator.

Example:

	alist = [new point, new point, new point]	# create list contains three objects 

	alist + [1,2,3]					# add another item to the list

	see "Item 4 is a list contains 3 items" + nl
	see alist[4] 

	add(alist , new point)
	alist + new point

	alist[5] { x = 100 y = 200 z = 300 }
	alist[6] { x = 50 y = 150 z = 250 }

	see "Object inside item 5" + nl
	see alist[5]
	see "Object inside item 6" + nl
	see alist[6]

	class point x y z

Output:

	Item 4 is a list contains 3 items
	1
	2
	3
	Object inside item 5
	x: 100.000000
	y: 200.000000
	z: 300.000000
	Object inside item 6
	x: 50.000000
	y: 150.000000
	z: 250.000000

Composition and Returning Objects and Lists by Reference

edit

When we use composition and have object as one of the class attributes, when we return that object it will be returned by reference.

if the called used the assignment operator, another copy of the object will be created.

The caller can avoid using the assignment operator and use the returned reference directly to access the object.

The same is done also if the attribute is a list (not object).

.. note:: Objects and Lists are treated using the same rules. When you pass them to function they are passed by reference, when you return them from functions they are returned by value except if it's an object attribute where a return by reference will be done.

Example:

	o1 = new Container
	myobj = o1.addobj()	# the assignment will create another copy
	myobj.x = 100
	myobj.y = 200
	myobj.z = 300
	see o1.aobjs[1]		# print the object inside the container	
	see myobj		# print the copy

	Class Container
		aObjs = []
		func addobj
			aobjs + new point
			return aobjs[len(aobjs)]	# return object by reference

	Class point 
		x  = 10
		y  = 20
		z  = 30

Output:

	x: 10.000000
	y: 20.000000
	z: 30.000000
	x: 100.000000
	y: 200.000000
	z: 300.000000

Example(2):

	func main
		o1 = new screen  {
			content[point()] { 
				x = 100 
				y = 200
				z = 300		
			}
			content[point()] { 
				x = 50 
				y = 150
				z = 250		
			}
		}
		see o1.content[1]
		see o1.content[2]

	Class Screen
		content = []
		func point
			content + new point
			return len(content)

	Class point 
		x  = 10
		y  = 20
		z  = 30

Output:

	x: 100.000000
	y: 200.000000
	z: 300.000000
	x: 50.000000
	y: 150.000000
	z: 250.000000

Example(3):

	func main
		o1 = New Screen  {
			point() { 		# access the object using reference 
				x = 100 
				y = 200
				z = 300		
			}
			point() { 		# access the object using reference 
				x = 50 
				y = 150
				z = 250		
			}
		}
		see o1.content[1]		
		see o1.content[2]

	Class Screen
		content = []
		func point
			content + new point
			return content[len(content)]	# return the object by reference

	Class point x=10 y=20 z=30

Output:

	x: 100.000000
	y: 200.000000
	z: 300.000000
	x: 50.000000
	y: 150.000000
	z: 250.000000

Executing code after the end of object access

edit

We can access an object using { } to use object attributes and methods.

if the object contains a method called BraceEnd(), it will be executed before the end of the object access.

Example:

	New Point { See "How are you?" + nl }

	Class Point x y z
		func braceend
			see "I'm fine, Thank you!" + nl

Output:

	How are you?
	I'm fine, Thank you!

Declarative Programming on the top of Object-Oriented

edit

The next features enable us to build and use declarative programming environment using nested structures on the top of object oriented

  • using {} to access the object attributes and methods
  • BraceEnd() Method
  • returning objects by reference
  • Setter/Getter Methods (optional)

Example:

	# Declartive Programming (Nested Structures)

	Screen() 
	{

		point() 
		{ 			
			x = 100 
			y = 200
			z = 300		
		}

		point() 
		{ 			 
			x = 50 
			y = 150
			z = 250		
		}
	}

	# Functions and Classes

	Func screen return new screen

	Class Screen

		content = []

		func point
			content + new point
			return content[len(content)]	

		func braceend
			see "I have " + len(content) + " points!"

	Class point 

		x=10 y=20 z=30

		func braceend		
			see self

Output:

	x: 100.000000
	y: 200.000000
	z: 300.000000
	x: 50.000000
	y: 150.000000
	z: 250.000000
	I have 2 points!

More beautiful Code

edit

We can get better results and a more beautiful code when we can avoid writing () after the method name when the methods doesn't take parameters. This feature is not provided directly by the Ring language because there is a difference between object methods and object attributes. We can get a similar effect on the syntax of the code when we define a getter method for the object attribute. For example instead of defining the point() method. we will define the point attribute then the getpoint() method that will be executed once you try to get the value of the point attribute. since we write the variable name direcly without () we can write point instead of point() and the method getpoint() will create the object and return the object reference for us.

Example:

	new Container 
	{
		Point 
		{ 
			x=10 
			y=20 
			z=30 
		}
	}

	Class Container
		aObjs = []
		point
		func getpoint
			aObjs + new Point
			return aObjs[len(aObjs)]

	Class Point x y z
		func braceend
			see "3D Point" + nl + x + nl + y + nl + z + nl

Output

	3D Point
	10
	20
	30



Lessons/Natural Language Programming

Natural Language Programming

edit

Using the Ring programming language, we can create Natural programming languages based on classes and objects.

History

edit

In 2010, I developed a new programming language called Supernova (developed using PWCT). This language uses a code that looks similar to Natural Language statements to create simple GUI applications. Now after five years, In the Ring programming language, we can get similar results, but now we have the ability to create/use code similar to Natural language statements in any domain that we like or need.

The Ring programming language comes with the Supernova sprite, but with more generalization and with mix of other languages sprites.

Example

edit

The next example presents how to create a class that define two instructions

The first instruction is : I want window

The second instruction is : Window title = <expr>

Also keywords that can be ignored like the 'the' keyword

	New App 
	{
		I want window 	
		The window title = "hello world"
	}

	Class App

		# Attributes for the instruction I want window
				i want window 
				nIwantwindow = 0
		# Attributes for the instruction Window title
		# Here we don't define the window attribute again
				title 
				nWindowTitle = 0
		# Keywords to ignore, just give them any value
				the=0	

		func geti
			if nIwantwindow = 0
				nIwantwindow++
			ok

		func getwant
			if nIwantwindow = 1
				nIwantwindow++
			ok

		func getwindow
			if nIwantwindow = 2
				nIwantwindow= 0
				see "Instruction : I want window" + nl
			ok
			if nWindowTitle = 0
				nWindowTitle++
			ok
	
		func settitle cValue
			if nWindowTitle = 1
				nWindowTitle=0
				see "Instruction : Window Title = " + cValue + nl
			ok

Output:

	Instruction : I want window
	Instruction : Window Title = hello world



Lessons/Functional Programming

Functional Programming

edit

In previous chapters we learned about Functions and Recursion.

In this chapter we are going to learn about more Functional Programming (FP) concepts like

  • Pure Functions
  • First-class functions
  • Higher-order functions
  • Anonymous and nested functions.
  • Equality of functions



Pure Functions

edit

We can create pure functions (functions that doesn't change the state) by the help of the assignment operator to copy variables (Lists & Objects) by value to create new variables instead of working on the original data that are passed to the function by reference.


Example:

	Func Main
		aList = [1,2,3,4,5]
		aList2 = square(aList)
		see "aList" + nl
		see aList
		see "aList2" + nl
		see aList2

	Func Square aPara
		a1 = aPara		# copy the list
		for x in a1
			x *= x
		next
		return a1		# return new list

Output:

	aList
	1
	2
	3
	4
	5
	aList2
	1
	4
	9
	16
	25

First-class Functions

edit

Functions inside the Ring programming language are first-class citizens, you can pass functions as parameters, return them as value or store them in variables.

We can pass/return the function by typing the function name as literal like "FunctionName" or :FunctionName for example.

We can pass/return functions using the variable that contains the function name.

We can call function from variables contains the function name using the Call command

Syntax:

	Call Variable([Parameters])

Example:

	Func Main
		see "before test2()" + nl
		f = Test2(:Test)
		see "after test2()" + nl
		call f()

	Func Test
		see "Message from test!" + nl

	Func Test2 f1
		call f1()
		See "Message from test2!" + nl
		return f1

Output:

	before test2()
	Message from test!
	Message from test2!
	after test2()
	Message from test!

Higher-order Functions

edit

Higher-order functions are the functions that takes other functions as parameters.

Example:

	Func Main
		times(5,:test)

	Func Test
		see "Message from the test function!" + nl

	Func Times nCount,F

		for x = 1 to nCount
			Call F()
		next

Output:

	Message from the test function!
	Message from the test function!
	Message from the test function!
	Message from the test function!
	Message from the test function!

Anonymous and Nested Functions

edit

Anonymous Functions are functions without names that can be passed as parameters to other functions or stored in variables.

Syntax:

	Func [Parameters] { [statements] }

Example:

	test( func x,y { 
				see "hello" + nl
				see "Sum : " + (x+y) + nl
		       } )

	new great { f1() }

	times(3, func { see "hello world" + nl } )

	func test x
		call x(3,3)
		see "wow!" + nl

	func times n,x
		for t=1 to n
			call x()
		next

	Class great
		func f1
			f2( func { see "Message from f1" + nl } )

		func f2 x
			call x()

Output:

	hello
	Sum : 6
	wow!
	Message from f1
	hello world
	hello world
	hello world

Example:

	Func Main
		aList = [1,2,3,4]
		Map (aList , func x { 
					return x*x 
				    } )
		see aList
		aList = [4,9,14,25]
		Map(aList, :myfilter )
		see aList
		aList = [11,12,13,14]
		Map (aList , func x {
			if x%2=0
				return "even"
			else
				return "odd"
			ok
		})
		see aList

	Func myfilter x
		if x = 9
			return "True"
		else
			return "False"
		ok

	Func Map aList,cFunc
		for x in aList
			x = call cFunc(x)
		next

Output:

	1
	4
	9
	16
	False
	True
	False
	False
	odd
	even
	odd
	even

Equality of functions

edit

We can test if function = function or not using the '=' or '!=' operators

Example:

	f1 = func { see "hello" + nl }

	f2 = func { see "how are you?" + nl }

	f3 = f1

	call f1()
	call f2()
	call f3()

	see (f1 = f2) + nl
	see (f2 = f3) + nl
	see (f1 = f3) + nl

Output:

	hello
	how are you?
	hello
	0
	0
	1



Lessons/Reflection and Meta-programming

Reflection and Meta-programming

edit

Since the Ring programming language is a dynamic language, we can get answers about the program code and we can modify our code during the runtime.

In this chapter we will learn about this and the available functions to use.

locals() Function

edit

We can get a list of variables names in the current scope using the locals() function.

Syntax:

	locals() --> a list contains the variables names in the current scope

Example:

	test("hello")

	func test cMsg

		see cMsg + nl

		x = 10
		y = 20
		z = 30

		see locals()

Output:

	hello
	cmsg
	x
	y
	z

globals() Function

edit

We can get a list of variables names in the global scope using the globals() function.

Syntax:

	
	globals() --> a list contains variables names in the global scope

Example:

	x=10 y=20 z=30
	test()

	func test
		see "message from test()" + nl +
		    "Global Variables:" + nl
		see globals()

Output:

	message from test()
	Global Variables:
	x
	y
	z

functions() Function

edit

We can get a list of functions names written in the Ring language using the functions() function.

Syntax:

	functions() --> a list contains functions names

Example:

	see functions()

	func f1
		see "f1" + nl

	func f2
		see "f2" + nl

	func f3 
		see "f3" + nl

Output:

	f1
	f2
	f3

cfunctions() Function

edit

We can get a list of functions names written in the C language using the cfunctions() function.

Syntax:

	cfunctions() --> a list contains functions names

Example:

	aList =  cfunctions()
	See "Count : " + len(aList) + nl
	for x in aList
		see x + "()" + nl
	next

Output:

	Count : 186
	len() 
	add() 
	del() 
	get() 
	clock()
	...

.. note:: The complete list is removed from the previous output.

islocal() Function

edit

We can check if a variable is defined in the local scope or not using the islocal() function.

Syntax:

	islocal(cVariableName) --> returns 1 if the variable is defined in the local scope
				   returns 0 if the variable is not defined in the local scope

Example:

	test()

	func test
		x=10 y=20
		see islocal("x") + nl + 
		    islocal("y") + nl + 
		    islocal("z") + nl

Output:

	1
	1
	0


isglobal() Function

edit

We can check if a variable is defined in the global scope or not using the isglobal() function.

Syntax:

	isglobal(cVariableName) --> returns 1 if the variable is defined in the global scope
				    returns 0 if the variable is not defined in the global scope

Example:

	x=10 y=20

	test()

	func test
		see isglobal("x") + nl + 
		    isglobal("y") + nl + 
		    isglobal("z") + nl

Output:

	1
	1
	0

isfunction() Function

edit

We can check if a Ring function is defined or not using the isfunction() function.

Syntax:

	isfunction(cFunctionName) --> returns 1 if the Ring function is defined
				      returns 0 if the Ring function is not defined

Example:

	see isfunction("f1") + nl + 
	    isfunction("f2") + nl + 
	    isfunction("f3") + nl

	func f1
		see "message from f1()" + nl

	func f2
		see "message from f2()" + nl

Output:

	1
	1
	0

iscfunction() Function

edit

We can check if a C function is defined or not using the iscfunction() function.

Syntax:

	iscfunction(cFunctionName) --> returns 1 if the C function is defined
				       returns 0 if the C function is not defined

Example:

	see iscfunction("len") + nl + 
  	    iscfunction("test") + nl

Output:

	1
	1
	0


packages() Function

edit

We can get a list of packages names using the packages() function.

Syntax:

	packages() --> a list contains packages names

Example:

	See packages()

	Package Package1
		Class class1
			Func f1

	Package Package2
		Class class1
			Func f1

	Package Package3
		Class class1
			Func f1

	Package Package4
		Class class1
			Func f1

Output:

	package1
	package2
	package3
	package4


ispackage() Function

edit

We can check if a package is defined or not using the ispackage() function.

Syntax:

	ispackage(cPackageName) --> returns 1 if the Package is defined
				    returns 0 if the Package is not defined

Example:

	See ispackage("package1") + nl + 
	    ispackage("package4") + nl + 
	    ispackage("package5") + nl +
	    ispackage("package3") + nl

	Package Package1
		Class class1
			Func f1

	Package Package2
		Class class1
			Func f1

	Package Package3
		Class class1
			Func f1

	Package Package4
		Class class1
			Func f1

Output:

	1
	1
	0
	1


classes() Function

edit

We can get a list of classes names using the classes() function.

Syntax:

	classes() --> a list contains classes names

Example:

	See classes()

	Class class1
		Func f1

	Class class2
		Func f1

	Class class3
		Func f1

Output:

	class1
	class2
	class3

isclass() Function

edit

We can check if a class is defined or not using the isclass() function.

Syntax:

	isclass(cClassName) -->  returns 1 if the Class is defined
				 returns 0 if the Class is not defined

Example:

	see isclass("class4") + nl + 
	    isclass("class3") + nl +
	    isclass("class2") + nl

	Class class1
		func f1

	class class2
		func f1

	class class3
		func f1

Output:

	0
	1
	1

packageclasses() Function

edit

We can get a list of classes names inside a package using the packageclasses() function.

Syntax:

	packageclasses(cPackageName) --> a list contains classes names inside the package

Example:

	see "classes in Package1" + nl
	see packageclasses("Package1")
	see "classes in Package2" + nl
	see packageclasses("Package2")

	Package Package1
		Class class1
			Func f1

	Package Package2
		Class class1
			Func f1
		Class class2
			Func f1
		Class class3
			func f1


Output:

	classes in Package1
	class1
	classes in Package2
	class1
	class2
	class3


ispackageclass() Function

edit

We can check if a class is defined inside package or not using the ispackageclass() function.

Syntax:

	ispackageclass(cPackageName,cClassName) -->  returns 1 if the Class is defined  
		  				     returns 0 if the Class is not defined

Example:

	see ispackageclass("package1","class1") + nl +
	    ispackageclass("package1","class2") + nl +
	    ispackageclass("package2","class1") + nl +
	    ispackageclass("package2","class2") + nl

	Package Package1
		Class class1
			Func f1

	Package Package2
		Class class1
			Func f1
		Class class2
			Func f1
		Class class3
			func f1

Output:

	1
	0
	1
	1

classname() Function

edit

We can know the class name of an object using the classname() function

Syntax:

	classname(object) --> Returns the object class name


Example:

	o1 = new point
	o2 = new rect

	see classname(o1) + nl		# print point
	see classname(o2) + nl		# print rect

	class point
	class rect

objectid() Function

edit

We can know the object id using the objectid() function

Syntax:

	objectid(object) --> Returns the object id

Example:

	o1 = new point
	see objectid(o1) + nl
	test(o1)

	func test v
		see objectid(v) + nl

	Class point x y z

Output:

	021B5808
	021B5808


We can check the variable to know if it's an object or not using the isobject() function

Syntax:

	isobject(variable) --> Returns True if it's an object, False if it's not


attributes() Function

edit

We can get the object attributes using the attributes() function

Syntax:

	attributes(object) --> Returns a list contains the object attributes

Example:

	o1 = new point
	aList = attributes(o1)		# we can use see attributes(o1)
	for t in aList see t next	# print xyz 
	Class Point x y z


We can get the object methods using the methods() function

Syntax:

	methods(object) --> Returns a list contains the object methods


Example:

	o1 = new test
	aList = methods(o1)

	for x in aList
		cCode = "o1."+x+"()"
		eval(cCode)
	next

	Class Test
		func f1
			see "hello from f1" + nl
		func f2
			see "hello from f2" + nl
		func f3
			see "hello from f3" + nl
		func f4
			see "hello from f4" + nl

Output:

	hello from f1
	hello from f2
	hello from f3
	hello from f4


isattribute() Function

edit

We can test if the object contains an attribute or not using the isattribute() function

Syntax:

	isattribute(object,cAttributeName) --> Returns True if the object contains the attribute

Example:

	o1 = new point

	see isattribute(o1,"x") + nl	# print 1
	see isattribute(o1,"t") + nl	# print 0
	see isattribute(o1,"y") + nl	# print 1
	see isattribute(o1,"z") + nl	# print 1

	class point x y z

isprivateattribute() Function

edit

We can test if the object contains a private attribute or not using the isprivateattribute() function

Syntax:

	isprivateattribute(object,cAttributeName) --> Returns True if the object 
						      contains the private attribute

Example:

	o1 = new person

	see isprivateattribute(o1,"name") + nl + 
	    isprivateattribute(o1,"address") + nl + 
	    isprivateattribute(o1,"phone") + nl + 
	    isprivateattribute(o1,"job") + nl + 
	    isprivateattribute(o1,"salary")

	Class Person
		name address phone
		private
			job salary

Output:

	0
	0
	0
	1
	1


ismethod() Function

edit

We can test if the object class contains a method or not using the ismethod() function

Syntax:

	ismethod(object,cMethodName) --> Returns True if the object class contains the method

Example:

	o1 = new point

	see ismethod(o1,"print") + nl		# print 1

	mylist = []
	mylist + new point

	see ismethod(mylist[1],"print") + nl	# print 1

	class point x y z
		func print
			see x + nl + y + nl + z + nl

isprivatemethod() Function

edit

We can test if the object class contains a private method or not using the isprivatemethod() function

Syntax:

	isprivatemethod(object,cMethodName) --> Returns True if the object class contains 
						the private method

Example:

	o1 = new Test

	see isprivatemethod(o1,"f1") + nl +
	    isprivatemethod(o1,"f2") 

	Class Test
		func  f1
			see "message from f1()" + nl
		private
			func f2
				see "message from f2()" + nl

Output:

	0
	1

addattribute() Function

edit

We can add an attribute (or a group of attributes) to the object state (not the class) using the addattribute() function

Syntax:

	AddAttribute(object,cAttributeName|aAttributesList)

Example(1):

	see new point {x=10 y=20 z=30}
	Class Point 
		AddAttribute(self,["x","y","z"])

Example(2):

	o1 = new point
	addattribute(o1,"x")
	addattribute(o1,"y")
	addattribute(o1,"z")
	see o1 {x=10 y=20 z=30}
	class point


Output:

	x: 10.000000
	y: 20.000000
	z: 30.000000



addmethod() Function

edit

We can add a method to the object class using the addmethod() function This method can be used with any object from the same class.

Syntax:

	AddMethod(Object,cNewMethodName,cMethodName|AnonymousFunction)

Example:

	o1 = new point { x=10 y=20 z=30 }

	addmethod(o1,"print", func { see x + nl + y + nl + z + nl } )

	o1.print()

	Class point
		x y z

Output:

	10
	20
	30

Instead of using anonymous function to add new method to the class, we can use the function name

Example:

	o1 = new point { x=10 y=20 z=30 }

	myfunc = func { see x + nl + y + nl + z + nl }

	addmethod(o1,"print", myfunc )
	addmethod(o1,"display", myfunc )
	addmethod(o1,"show", myfunc )

	o1.print()
	o1.display()
	o1.show()

	Class point
		x y z

Output:

	10
	20
	30
	10
	20
	30
	10
	20
	30

Since we add the method to the class, any object from that class can use this method

Example:

	o1 = new point { x=10 y=20 z=30 }
	o2 = new point { x=100 y=200 z=300 }
	o3 = new point { x=50 y=150 z=250 }

	addmethod(o1,"print", func { see x + nl + y + nl + z + nl } )

	o1.print()
	o2.print()
	o3.print()

	Class point
		x y z

Output:

	10
	20
	30
	100
	200
	300
	50
	150
	250

getattribute() function

edit

We can get the object attribute value using the getattribute() function

Syntax:

	GetAttribute(oObject,cAttributeName) ---> Attribute Value

Example:

	o1 = new point

	see getattribute(o1,"name") + nl +
	    getattribute(o1,"x") + nl +
	    getattribute(o1,"y") + nl + 
	    getattribute(o1,"z") + nl

	Class Point
		x=10 y=20 z=30
		name = "3D-Point"

Output:

	3D-Point
	10
	20
	30

setattribute() function

edit

We can set the object attribute value using the setattribute() function

Syntax:

	SetAttribute(oObject,cAttributeName,Value)

Example:

	o1 = new person
	setattribute(o1,"cName","Mahmoud")
	setattribute(o1,"nSalary",1000000)
	setattribute(o1,"aColors",["white","blue","yellow"])

	see o1
	see o1.aColors

	Class Person
		cName
		nSalary
		aColors

Output:

	cname: Mahmoud
	nsalary: 1000000.000000
	acolors: List...
	white
	blue
	yellow


mergemethods() Function

edit

We can share methods between classes without inheritance using the MergeMethods() function

This function merge class methods to another class.

Syntax:

	MergeMethods(cClassNameDestination,cClassNameSource)

Example:

	mergemethods("count","share")
	mergemethods("count2","share")

	o1 = new count  { test() }
	o1 = new count2 { test() }

	Class Share
		func one
			see "one" + nl
		func two
			see "two" + nl
		func three
			see "three" + nl

	Class Display
		Func printline
			see copy("*",20) + nl

	Class Count from Display
		Func test
			printline()
			one()
			two()
			three()
			printline()

	Class Count2 from Display
		Func test
			three()
			two()
			one()
			printline()

Output:

	********************
	one
	two
	three
	********************
	three
	two
	one
	********************



Lessons/Extension using the C/C++ languages

Extension using the C/C++ languages

edit

We can extend the Ring Virtual Machine (RingVM) by adding new functions written in the C programming language or C++.

The RingVM comes with many functions written in C that we can call like any Ring function.

We can extend the language by writing new functions then rebuilding the RingVM again, or we can create shared library (DLL/So) file to extend the RingVM without the need to rebuild it.

The Ring language source code comes with two files to add new modules to the RingVM, ring_ext.h and ring_ext.c

ring_ext.h

edit

The file ring_ext.h contains constants that we can change to include/exclude modules during the build process.

	#ifndef ringext_h
	#define ringext_h
	/* Constants */
	#define RING_VM_LISTFUNCS 	1
	#define RING_VM_REFMETA 	1
	#define RING_VM_MATH		1
	#define RING_VM_FILE 		1
	#define RING_VM_OS 		1
	#define RING_VM_MYSQL 		1
	#define RING_VM_ODBC 		1
	#define RING_VM_OPENSSL		1
	#define RING_VM_CURL 		1
	#define RING_VM_DLL 		1
	#endif



ring_ext.c

edit

The file ring_ext.c check constants defined in ring_ext.h before calling the start-up function in each module.

Each module contains a function that register the module functions in the RingVM.

	#include "ring.h"

	void ring_vm_extension ( RingState *pRingState )
	{
		/* Reflection and Meta-programming */
		#if RING_VM_REFMETA
			ring_vm_refmeta_loadfunctions(pRingState);
		#endif
		/* List Functions */
		#if RING_VM_LISTFUNCS
			ring_vm_listfuncs_loadfunctions(pRingState);
		#endif
		/* Math */
		#if RING_VM_MATH
			ring_vm_math_loadfunctions(pRingState);
		#endif
		/* File */
		#if RING_VM_FILE
			ring_vm_file_loadfunctions(pRingState);
		#endif
		/* OS */
		#if RING_VM_OS
			ring_vm_os_loadfunctions(pRingState);
		#endif
		/* MySQL */
		#if RING_VM_MYSQL
			ring_vm_mysql_loadfunctions(pRingState);
		#endif
		/* ODBC */
		#if RING_VM_ODBC
			ring_vm_odbc_loadfunctions(pRingState);
		#endif
		/* OPENSSL */
		#if RING_VM_OPENSSL
			ring_vm_openssl_loadfunctions(pRingState);
		#endif
		/* CURL */
		#if RING_VM_CURL
			ring_vm_curl_loadfunctions(pRingState);
		#endif
		/* DLL */
		#if RING_VM_DLL
			ring_vm_dll_loadfunctions(pRingState);
		#endif
	}

Module Organization

edit

Each module starts by include the ring header file (ring.h). This files contains the Ring API that we can use to extend the RingVM.

Each module comes with a function to register the module functions in the RingVM The registration is done by using ring_vm_funcregister() function.


The ring_vm_funcregister() function takes two parameters, the first is the function name that will be used by Ring programs to call the function. The second parameter is the function pointer in the C program.

for example, the ring_vmmath.c module contains the next code to register the module functions

	#include "ring.h"

	void ring_vm_math_loadfunctions ( RingState *pRingState )
	{
		ring_vm_funcregister("sin",ring_vm_math_sin);
		ring_vm_funcregister("cos",ring_vm_math_cos);
		ring_vm_funcregister("tan",ring_vm_math_tan);
		ring_vm_funcregister("asin",ring_vm_math_asin);
		ring_vm_funcregister("acos",ring_vm_math_acos);
		ring_vm_funcregister("atan",ring_vm_math_atan);
		ring_vm_funcregister("atan2",ring_vm_math_atan2);
		ring_vm_funcregister("sinh",ring_vm_math_sinh);
		ring_vm_funcregister("cosh",ring_vm_math_cosh);
		ring_vm_funcregister("tanh",ring_vm_math_tanh);
		ring_vm_funcregister("exp",ring_vm_math_exp);
		ring_vm_funcregister("log",ring_vm_math_log);
		ring_vm_funcregister("log10",ring_vm_math_log10);
		ring_vm_funcregister("ceil",ring_vm_math_ceil);
		ring_vm_funcregister("floor",ring_vm_math_floor);
		ring_vm_funcregister("fabs",ring_vm_math_fabs);
		ring_vm_funcregister("pow",ring_vm_math_pow);
		ring_vm_funcregister("sqrt",ring_vm_math_sqrt);
		ring_vm_funcregister("unsigned",ring_vm_math_unsigned);
		ring_vm_funcregister("decimals",ring_vm_math_decimals);
		ring_vm_funcregister("murmur3hash",ring_vm_math_murmur3hash);
	}

.. tip:: Remember that the function ring_vm_math_loadfunctions() will be called by the ring_vm_extension() function (in the ring_ext.c file).

Function Structure

edit

Each module function may contains the next steps

1 - Check Parameters Count

2 - Check Parameters Type

3 - Get Parameters Values

4 - Execute Code/Call Functions

5 - Return Value

The structure is very similar to any function (Input - Process - Output) But here we will use the Ring API for the steps 1,2,3 and 5.



Check Parameters Count

edit

We can check the parameters count using the RING_API_PARACOUNT macro.

We can compare RING_API_PARACOUNT with any numeric value using == or != operators.


Example:

	if ( RING_API_PARACOUNT != 1 ) {
		/* code */
	}


Example:

	if ( RING_API_PARACOUNT == 1 ) {
		/* code */
	}



Display Error Message

edit

We can display error messages using the RING_API_ERROR() function.

The function will display the error and end the execution of the program.

.. note:: the behaviour of this function can be changed by the Ring code using Try/Catch/Done statements, so in your C code, use Return after this function.


Syntax:

	RING_API_ERROR(const char *cErrorMsg);

The Ring API comes with some of predefined error messages that we can use

	#define RING_API_MISS1PARA "Bad parameters count, the function expect one parameter"
	#define RING_API_MISS2PARA "Bad parameters count, the function expect two parameters"
	#define RING_API_MISS3PARA "Bad parameters count, the function expect three parameters"
	#define RING_API_MISS4PARA "Bad parameters count, the function expect four parameters"
	#define RING_API_BADPARATYPE 	"Bad parameter type!"
	#define RING_API_BADPARACOUNT 	"Bad parameters count!"
	#define RING_API_BADPARARANGE 	"Bad parameters value, error in range!"
	#define RING_API_NOTPOINTER 	"Error in parameter, not pointer!"
	#define RING_API_NULLPOINTER	"Error in parameter, NULL pointer!"
	#define RING_API_EMPTYLIST 	"Bad parameter, empty list!"



Check Parameters Type

edit

We can check the parameter type using the next functions

	int RING_API_ISNUMBER(int nParameterNumber);
	int RING_API_ISSTRING(int nParameterNumber);
	int RING_API_ISLIST(int nParameterNumber);
	int RING_API_ISPOINTER(int nParameterNumber);

The output of these functions will be 1 (True) or 0 (False).



Get Parameters Values

edit

We can get paramters values using the next functions

	double RING_API_GETNUMBER(int nParameterNumber);
	const char *RING_API_GETSTRING(int nParameterNumber);
	int RING_API_GETSTRINGSIZE(int nParameterNumber);
	List *RING_API_GETLIST(int nParameterNumber);
	void *RING_API_GETCPOINTER(int nParameterNumber, const char *cPoinerType);
	int RING_API_GETPOINTERTYPE(int nParameterNumber);



Return Value

edit

We can return values from our function using the next functions.

	RING_API_RETNUMBER(double nValue);
	RING_API_RETSTRING(const char *cString);
	RING_API_RETSTRING2(const char *cString,int nStringSize);
	RING_API_RETLIST(List *pList);
	RING_API_RETCPOINTER(void *pValue,const char *cPointerType);



Function Prototype

edit

When we define new function to be used for RingVM extension, we use the next prototype

	void my_function_name( void *pPointer );


	RING_FUNC(my_function_name);



Sin() Function Implementation

edit

The next code represents the sin() function implementation using the Ring API and the sin() C function.


	void ring_vm_math_sin ( void *pPointer )
	{
		if ( RING_API_PARACOUNT != 1 ) {
			RING_API_ERROR(RING_API_MISS1PARA);
			return ;
		}
		if ( RING_API_ISNUMBER(1) ) {
			RING_API_RETNUMBER(sin(RING_API_GETNUMBER(1)));
		} else {
			RING_API_ERROR(RING_API_BADPARATYPE);
		}
	}



Fopen() and Fclose() Functions Implementation

edit

The next code represents the fopen() function implementation using the Ring API and the fopen() C Function.

The function takes two parameters, the first parameter is the file name as string. The second parameter is the mode as string.

In the file ring_vmfile.h we have some constants to use as the pointer type like

	#define RING_VM_POINTER_FILE 	"file"
	#define RING_VM_POINTER_FILEPOS "filepos"

The function implementation in ring_vmfile.c

	void ring_vm_file_fopen ( void *pPointer )
	{
		FILE *fp  ;
		if ( RING_API_PARACOUNT != 2 ) {
			RING_API_ERROR(RING_API_MISS2PARA);
			return ;
		}
		if ( RING_API_ISSTRING(1) && RING_API_ISSTRING(2) ) {
			fp = fopen(RING_API_GETSTRING(1),RING_API_GETSTRING(2));
			RING_API_RETCPOINTER(fp,RING_VM_POINTER_FILE);
		} else {
			RING_API_ERROR(RING_API_BADPARATYPE);
		}
	}


The next code represents the fclose() function implementation

	void ring_vm_file_fclose ( void *pPointer )
	{
		FILE *fp  ;
		if ( RING_API_PARACOUNT != 1 ) {
			RING_API_ERROR(RING_API_MISS1PARA);
			return ;
		}
		if ( RING_API_ISPOINTER(1) ) {
			fp = (FILE *) RING_API_GETCPOINTER(1,RING_VM_POINTER_FILE) ;
			if ( fp != NULL ) {
				RING_API_RETNUMBER(fclose(fp));
				RING_API_SETNULLPOINTER(1);
			}
		} else {
			RING_API_ERROR(RING_API_BADPARATYPE);
		}
	}

From fopen() and fclose() implementation we learned

1 - how to return C pointer using RING_API_RETCPOINTER() function

2 - how to check if the parameter is a pointer using the RING_API_ISPOINTER() function

3 - how to get C pointer value using the RING_API_GETCPOINTER() function

4 - how to set the C pointer variable (in RingVM) to NULL using the RING_API_SETNULLPOINTER() function



Ring API - List Functions

edit

In this section we will learn about the list functions provided by the Ring API to create new lists and manipulate the list items.

	List * ring_list_new ( int nSize ) ;
	void ring_list_newitem ( List *pList ) ;
	Item * ring_list_getitem ( List *pList,int index ) ;
	List * ring_list_delete ( List *pList ) ;
	void ring_list_deleteitem ( List *pList,int index ) ;
	void ring_list_print ( List *pList ) ;
	int ring_list_gettype ( List *pList, int index ) ;
	void ring_list_setint ( List *pList, int index ,int number ) ;
	void ring_list_addint ( List *pList,int x ) ;
	void ring_list_setpointer ( List *pList, int index ,void *pValue ) ;
	void ring_list_addpointer ( List *pList,void *pValue ) ;
	void ring_list_setfuncpointer ( List *pList, int index ,void (*pFunc)(void *) ) ;
	void ring_list_addfuncpointer ( List *pList,void (*pFunc)(void *) ) ;
	int ring_list_isfuncpointer ( List *pList, int index ) ;
	void ring_list_setdouble ( List *pList, int index ,double number ) ;
	void ring_list_adddouble ( List *pList,double x ) ;
	void ring_list_setstring ( List *pList, int index ,const char *str ) ;
	void ring_list_setstring2 ( List *pList, int index ,const char *str,int nStrSize ) ;
	void ring_list_addstring ( List *pList,const char *str ) ;
	void ring_list_addstring2 ( List *pList,const char *str,int nStrSize ) ;
	List * ring_list_newlist ( List *pList ) ;
	List * ring_list_getlist ( List *pList, int index ) ;
	void ring_list_setlist ( List *pList, int index ) ;
	void ring_list_setactiveitem ( List *pList, Items *pItems, int index ) ;
	void ring_list_copy ( List *pNewList, List *pList ) ;
	int ring_list_isnumber ( List *pList, int index ) ;
	int ring_list_isstring ( List *pList, int index ) ;
	int ring_list_islist ( List *pList, int index ) ;
	int ring_list_ispointer ( List *pList, int index ) ;
	void ring_list_deleteallitems ( List *pList ) ;
	void ring_list_insertitem ( List *pList,int x ) ;
	void ring_list_insertint ( List *pList,int nPos,int x ) ;
	void ring_list_insertdouble ( List *pList,int nPos,double x ) ;
	void ring_list_insertpointer ( List *pList,int nPos,void *pValue ) ;
	void ring_list_insertstring ( List *pList,int nPos,const char *str ) ;
	void ring_list_insertstring2 ( List *pList,int nPos,const char *str,int nStrSize ) ;
	void ring_list_insertfuncpointer ( List *pList,int nPos,void (*pFunc)(void *) ) ;
	List * ring_list_insertlist ( List *pList,int nPos ) ;
	int ring_list_isiteminsidelist ( List *pList,Item *pItem ) ;
	int ring_list_findstring ( List *pList,const char *str,int nColumn ) ;
	int ring_list_finddouble ( List *pList,double nNum1,int nColumn ) ;
	void ring_list_sortnum ( List *pList,int left,int right,int nColumn ) ;
	void ring_list_sortstr ( List *pList,int left,int right,int nColumn ) ;
	int ring_list_binarysearchnum ( List *pList,double nNum1,int nColumn ) ;
	int ring_list_binarysearchstr ( List *pList,const char *cFind,int nColumn ) ;
	void ring_list_swap ( List *pList,int x,int y ) ;
	double ring_list_getdoublecolumn ( List *pList,int nIndex,int nColumn ) ;
	char * ring_list_getstringcolumn ( List *pList,int nIndex,int nColumn ) ;
	void ring_list_genarray ( List *pList ) ;
	void ring_list_deletearray ( List *pList ) ;
	void ring_list_genhashtable ( List *pList ) ;
	void ring_list_genhashtable2 ( List *pList ) ;
	void ring_list_refcopy ( List *pNewList, List *pList ) ;
	void ring_list_clear ( List *pList ) ;
	/* Macro */
	ring_list_isdouble(pList,index)
	ring_list_isint(pList,index) 
	ring_list_deletelastitem(x)
	ring_list_gethashtable(x) 
	ring_list_getint(pList,index)
	ring_list_getpointer(pList,index)
	ring_list_getfuncpointer(pList,index)
	ring_list_callfuncpointer(pList,index,x)
	ring_list_getdouble(pList,index) 
	ring_list_getstring(pList,index) 
	ring_list_getstringobject(pList,index) 
	ring_list_getstringsize(pList,index)
	ring_list_getsize(x) (x->nSize)



Ring API - String Functions

edit

In this section we will learn about the string functions provided by the Ring API to create new string and manipulate the string content.

	String * ring_string_new ( const char *str ) ;
	String * ring_string_new2 ( const char *str,int nStrSize ) ;
	String * ring_string_delete ( String *pString ) ;
	int ring_string_size ( String *pString ) ;
	void ring_string_set ( String *pString,const char *str ) ;
	void ring_string_set2 ( String *pString,const char *str,int nStrSize ) ;
	void ring_string_add ( String *pString,const char *str ) ;
	void ring_string_add2 ( String *pString,const char *str,int nStrSize ) ;
	void ring_string_print ( String *pString ) ;
	void ring_string_setfromint ( String *pString,int x ) ;
	char * ring_string_lower ( char *cStr ) ;
	char * ring_string_upper ( char *cStr ) ;
	char * ring_string_lower2 ( char *cStr,int nStrSize ) ;
	char * ring_string_upper2 ( char *cStr,int nStrSize ) ;
	char * ring_string_find ( char *cStr1,char *cStr2 ) ;
	char * ring_string_find2 ( char *cStr1,int nStrSize1,char *cStr2,int nStrSize2 ) ;
	/* Macro */
	ring_string_tolower(x)
	ring_string_toupper(x)
	ring_string_get(x)



MySQL_Columns() Function Implementation

edit

The next code presents the MySQL_Columns() function implementation.

This function returns table columns information.

	void ring_vm_mysql_columns ( void *pPointer )
	{
		MYSQL *con  ;
		MYSQL_RES *result  ;
		int nColumns,x  ;
		MYSQL_ROW row  ;
		MYSQL_FIELD *field  ;
		List *pList, *pList2  ;
		if ( RING_API_PARACOUNT != 1 ) {
			RING_API_ERROR(RING_API_MISS1PARA);
			return ;
		}
		if ( RING_API_ISPOINTER(1) ) {
			con = (MYSQL *) RING_API_GETCPOINTER(1,RING_VM_POINTER_MYSQL) ;
			if ( con == NULL ) {
				return ;
			}
			result = mysql_store_result(con);
			if ( result == NULL ) {
				RING_API_RETNUMBER(0);
				return ;
			}
			pList = RING_API_NEWLIST ;
			nColumns = mysql_num_fields(result);
			if ( row = mysql_fetch_row(result) ) {
				while ( field = mysql_fetch_field(result) ) {
					pList2 = ring_list_newlist(pList);
					ring_list_addstring(pList2,field->name);
					ring_list_adddouble(pList2,field->length);
					ring_list_adddouble(pList2,field->type);
					ring_list_adddouble(pList2,field->flags);
				}
			}
			mysql_free_result(result);
			RING_API_RETLIST(pList);
		} else {
			RING_API_ERROR(RING_API_BADPARATYPE);
		}
	}

Lists are of type List, in the previoud function we declared two pointers of type List using List *pList, *pList2;

.. note:: The function uses RING_API_NEWLIST to create new list instead of ring_list_new() to create the list in Temp. Memory related to the function scope. This way we can return the list from the function. Also we don't delete the list, if it's stored in a variable by Ring Code it will be saved, if not it will be automatically deleted by RingVM.


The list can contains sub lists, we used the function ring_list_newlist() to create a sublist.

The function ring_list_addstring() is used to add string items to the list/sublist.

The function ring_list_adddouble() is used to add numeric items to the list/sublist.

.. note:: All numeric items in lists returned from RingVM extension functions must be of type double and added to the list using ring_list_adddouble() function.


We return the list from the extension function using the RING_API_RETLIST() function.

Dynamic/Shared Libraries (DLL/So) and LoadLib() function

edit

Instead of rebuilding the RingVM after writing new functions using C/C++ and the Ring API, we can create a DLL/So file and dynamically use the functions provided by this file in the runtime using the LoadLib() function.

Dynamic library example in C

	#include "ring.h"

	RING_DLL __declspec(dllexport) 

	RING_FUNC(ring_ringlib_dlfunc)
	{
		printf("Message from dlfunc");
	}

	RING_DLL void ringlib_init(RingState *pRingState)
	{
		ring_vm_funcregister("dlfunc",ring_ringlib_dlfunc); 
	}

the idea is to create the ringlib_init() function, this function will be called by the RingVM when we use the generated DLL file though the LoadLib() function.

Inside the ringlib_init() function we can register the module function or call a function that do the registration process for all of the module functions.

The next Ring code demonstrates how to use the DLL library during the runtime.

	See "Dynamic DLL" + NL
	LoadLib("ringlib.dll")
	dlfunc()

Output:

	Dynamic DLL
	Message from dlfunc



Lessons/Embedding Ring Interpreter in C/C++ Programs

Embedding Ring Interpreter in C/C++ Programs

edit

We can call the Ring interpreter from C/C++ programs using the next functions

	RingState *ring_state_init();
	ring_state_runcode(RingState *pState,const char *cCode);
	ring_state_delete(RingState *pState);



Ring State

edit

The idea is to use the ring_state_init() to create new state for the Ring Interpreter then call the ring_state_runcode() function to execut Ring code using the same state. When we are done, we call the ring_state_delete() to free the memory.

Example:

	#include "ring.h"
	#include "stdlib.h"
	int main(int argc, char *argv[])
	{	
	  RingState *pState = ring_state_init();
	  printf("welcome\n");
	  ring_state_runcode(pState,"see 'hello world from the ring programming language'+nl");
	  ring_state_delete(pState);
	}

Output:

	welcome
	hello world from the ring programming language



Ring State Functions

edit

The Ring API comes with the next functions to create and delete the state. Also we have functions to create new variables and get variables values.

	RingState * ring_state_init ( void ) ;
	RingState * ring_state_delete ( RingState *pRingState ) ;
	void ring_state_runcode ( RingState *pRingState,const char *cStr ) ;
	List * ring_state_findvar ( RingState *pRingState,const char *cStr ) ;
	List * ring_state_newvar ( RingState *pRingState,const char *cStr ) ;
	void ring_state_main ( int argc, char *argv[] ) ;
	void ring_state_runfile ( RingState *pRingState,const char *cFileName ) ;



Ring State Variables

edit

We can create more than one ring state in the same program and we can create and modify variable values.

To get the variable list we can use the ring_state_findvar() function.

To create new variable we can use the ring_state_newvar() function.

Example:

	#include "ring.h"
	#include "stdlib.h"
	
	int main(int argc, char *argv[])
	{
	  List *pList;

  	  RingState *pState = ring_state_init();
	  RingState *pState2 = ring_state_init();

	  printf("welcome\n");
	  ring_state_runcode(pState,"see 'hello world from the ring programming language'+nl");

	  printf("Again from C we will call ring code\n");
	  ring_state_runcode(pState,"for x = 1 to 10 see x + nl next");

	  ring_state_runcode(pState2,"for x = 1 to 5 see x + nl next");

	  printf("Now we will display the x variable value from ring code\n");
	  ring_state_runcode(pState,"see 'x value : ' + x + nl ");
	  ring_state_runcode(pState2,"see 'x value : ' + x + nl ");

	  pList = ring_state_findvar(pState,"x");

	  printf("Printing Ring variable value from C, %.0f\n",
		  	ring_list_getdouble(pList,RING_VAR_VALUE));

	  printf("now we will set the ring variable value from C\n");
	  ring_list_setdouble(pList,RING_VAR_VALUE,20);

	  ring_state_runcode(pState,"see 'x value after update : ' + x + nl ");

	  pList = ring_state_newvar(pState,"v1");
	  ring_list_setdouble(pList,RING_VAR_VALUE,10);	

	  pList = ring_state_newvar(pState,"v2");
	  ring_list_setdouble(pList,RING_VAR_VALUE,20);

	  ring_state_runcode(pState,"see 'v1 + v2 = ' see v1+v2 see nl");

	  ring_state_runcode(pState,"see 'end of test' + nl");

	  ring_state_delete(pState);
	  ring_state_delete(pState2);
	}

Output:

	welcome
	hello world from the ring programming language
	Again from C we will call ring code
	1
	2
	3
	4
	5
	6
	7
	8
	9
	10
	1
	2
	3
	4
	5
	Now we will display the x variable value from ring code
	x value : 11
	x value : 6
	Printing Ring variable value from C, 11
	now we will set the ring variable value from C
	x value after update : 20
	v1 + v2 = 30
	end of test



Lessons/Command Line Options

Command Line Options

edit

The ring interpreter takes source code file (*.ring) as input to execute, also the interpreter provide other options like

============	=======================================================
Option          Description	
============	=======================================================
-tokens         Print a list of tokens in the source code file
-rules          Print grammar rules applied on the tokens
-ic             Print the intermediate byte code (before execution)
-icfinal        Print the final byte code (after execution)
-cgi            Print http response header before error messages
-norun          Don't run the program after compiling
-ins            Print instruction operation code before execution
-performance    Print clock before and after program execution
============	=======================================================

Printing Tokens

edit

Example:

	Func Main
		See "Hello World" + nl
		for x = 1 to 10
			see x + nl
		next
		test()

	func test
		see "welcome" + nl
		o1 = new point { x=10 y=20 z=30 }
		see o1

	class point x y z

Command:

	ring test.ring -tokens -norun

Output:

	===================================================
	Tokens - Generated by the Scanner
	===================================================

	   Keyword : FUNC
	Identifier : main
	   EndLine
	   Keyword : SEE
	   Literal : Hello World
	  Operator : +
	Identifier : nl
	   EndLine
	   Keyword : FOR
	Identifier : x
	  Operator : =
	    Number : 1
	   Keyword : TO
	    Number : 10
	   EndLine
	   Keyword : SEE
	Identifier : x
	  Operator : +
	Identifier : nl
	   EndLine
	   Keyword : NEXT
	   EndLine
	Identifier : test
	  Operator : (
	  Operator : )
	   EndLine
	   Keyword : FUNC
	Identifier : test
	   EndLine
	   Keyword : SEE
	   Literal : welcome
	  Operator : +
	Identifier : nl
	   EndLine
	Identifier : o1
	  Operator : =
	   Keyword : NEW
	Identifier : point
	  Operator : {
	Identifier : x
	  Operator : =
	    Number : 10
	Identifier : y
	  Operator : =
	    Number : 20
	Identifier : z
	  Operator : =
	    Number : 30
	  Operator : }
	   EndLine
	   Keyword : SEE
	Identifier : o1
	   EndLine
	   Keyword : CLASS
	Identifier : point
	Identifier : x
	Identifier : y
	Identifier : z
	   EndLine

	===================================================

Printing Rules

edit

Command:

	ring test.ring -rules -norun

Output:

	===================================================
	Grammar Rules Used by The Parser
	===================================================

	Rule : Program --> {Statement}

	Line 1
	Rule : Statement  --> 'Func' Identifier [ParaList]

	Line 2
	Rule : Factor --> Literal
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus]
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : Arithmetic --> Arithmetic + Arithmetic
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Statement  --> 'See' Expr

	Line 3
	Rule : Factor --> Number
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Factor --> Number
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Statement  --> 'For' Identifier '=' Expr to Expr ['step' Expr]

	Line 4
	Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus]
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus]
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : Arithmetic --> Arithmetic + Arithmetic
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Statement  --> 'See' Expr

	Line 5
	Rule : Next --> 'Next'

	Line 6
	Rule : Mixer -> '(' [Expr { ',' Expr} ] ')'

	Line 8
	Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus]
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Statement  --> Expr
	Rule : Statement  --> 'Func' Identifier [ParaList]

	Line 9
	Rule : Factor --> Literal
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus]
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : Arithmetic --> Arithmetic + Arithmetic
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Statement  --> 'See' Expr

	Line 10
	Rule : Factor --> New Identifier {'.' Identifier }
	Rule : Mixer --> '{' {Statement} BraceEnd
	Rule : Factor --> Number
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Assignment -> '=' Expr
	Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus]
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Statement  --> Expr
	Rule : Factor --> Number
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Assignment -> '=' Expr
	Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus]
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Statement  --> Expr
	Rule : Factor --> Number
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Assignment -> '=' Expr
	Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus]
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Statement  --> Expr
	Rule : BraceEnd --> '}'
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Assignment -> '=' Expr
	Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus]
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Statement  --> Expr

	Line 11
	Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus]
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Statement  --> 'See' Expr

	Line 13
	Rule : Statement  --> 'Class' Identifier
	Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus]
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Statement  --> Expr
	Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus]
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Statement  --> Expr
	Rule : Factor --> Identifier [ {Mixer} | Assignment | PlusPlus | MinusMinus]
	Rule : Range --> Factor
	Rule : Term --> Range
	Rule : Arithmetic --> Term
	Rule : BitShift --> Arithmetic
	Rule : BitAnd --> BitShift
	Rule : BitOrXOR -->  BitAnd
	Rule : Compare --> BitOrXOR
	Rule : EqualOrNot --> Compare
	Rule : LogicNot -> EqualOrNot
	Rule : Expr --> LogicNot
	Rule : Statement  --> Expr

	===================================================


Printing Intermediate Code

edit

Command:

	ring test.ring -ic -norun

Output:

	===================================================
	Byte Code - Before Execution by the VM
	===================================================

		 PC      OPCode        Data

		  1  ReturnNull
		  2        Func    main
		  3     NewLine       2
		  4     FuncExE
		  5       PushC   Hello World
		  6       LoadA      nl      0
		  7       PushV
		  8         SUM       0
		  9       Print
		 10     NewLine       3
		 11    ExitMark      29     28
		 12  LoadAFirst       x
		 13       PushN   1.000000
		 14  BeforeEqual       0
		 15  Assignment
		 16       PushN   1.000000
		 17  StepNumber
		 18  JumpVarLENum       x  10.000000    29
		 19     NewLine       4
		 20     FuncExE
		 21       LoadA       x      0
		 22       PushV
		 23       LoadA      nl      0
		 24       PushV
		 25         SUM       0
		 26       Print
		 27     NewLine       5
		 28     IncJump       x     18
		 29  POPExitMark
		 30     POPStep
		 31     NewLine       6
		 32    LoadFunc    test
		 33        Call       0
		 34  NoOperation
		 35     NewLine       8
		 36       PushV
		 37   FreeStack
		 38  ReturnNull
		 39        Func    test
		 40     NewLine       9
		 41     FuncExE
		 42       PushC   welcome
		 43       LoadA      nl      0
		 44       PushV
		 45         SUM       0
		 46       Print
		 47     NewLine      10
		 48       LoadA      o1      0
		 49  AssignmentPointer
		 50         New   point
		 51    SetScope
		 52       PushV
		 53  BraceStart
		 54       LoadA       x      0     58
		 55  AssignmentPointer
		 56       PushN   10.000000
		 57  BeforeEqual       0
		 58  Assignment       0      0
		 59   FreeStack
		 60       LoadA       y      0     64
		 61  AssignmentPointer
		 62       PushN   20.000000
		 63  BeforeEqual       0
		 64  Assignment       0      0
		 65   FreeStack
		 66       LoadA       z      0     70
		 67  AssignmentPointer
		 68       PushN   30.000000
		 69  BeforeEqual       0
		 70  Assignment       0      0
		 71   FreeStack
		 72    LoadFunc   ismethod
		 73       LoadA    self      0
		 74       PushV
		 75       PushC   braceend
		 76        Call
		 77  NoOperation
		 78       PushV
		 79       JumpZ      85
		 80    LoadFunc   braceend
		 81        Call
		 82  NoOperation
		 83       PushV
		 84   FreeStack
		 85    BraceEnd
		 86   FreeStack
		 87     NewLine      11
		 88     FuncExE
		 89       LoadA      o1      0
		 90       PushV
		 91       Print
		 92     NewLine      13
		 93  ReturnNull
		 94       Class   point  006E8BC0
		 95    NewLabel
		 96       LoadA       x      0
		 97       PushV
		 98   FreeStack
		 99       LoadA       y      0
		100       PushV
		101   FreeStack
		102       LoadA       z      0
		103       PushV
		104   FreeStack
		105  ReturnNull

	===================================================


Printing Final Intermediate Code

edit

Command:

	ring test.ring -icfinal

Output:

	Hello World
	1
	2
	3
	4
	5
	6
	7
	8
	9
	10
	welcome
	x: 10.000000
	y: 20.000000
	z: 30.000000

	===================================================
	Byte Code - After Execution by the VM
	===================================================

		 PC      OPCode        Data

		  1  ReturnNull
		  2        Func    main
		  3     NewLine       2
		  4     FuncExE
		  5       PushC   Hello World
		  6       PushP   007D3670      0
		  7       PushV
		  8         SUM       0
		  9       Print
		 10     NewLine       3
		 11    ExitMark      29     28
		 12  LoadAFirst       x
		 13       PushN   1.000000
		 14  BeforeEqual       0
		 15  Assignment
		 16       PushN   1.000000
		 17  StepNumber
		 18  JumpVarLPLENum       x  10.000000    29
		 19     NewLine       4
		 20     FuncExE
		 21  PushPLocal       x      0
		 22       PushV
		 23       PushP   007D3670      0
		 24       PushV
		 25         SUM       0
		 26       Print
		 27     NewLine       5
		 28   IncLPJump       x     18
		 29  POPExitMark
		 30     POPStep
		 31     NewLine       6
		 32   LoadFuncP    test
		 33        Call       0
		 34  NoOperation
		 35     NewLine       8
		 36       PushV
		 37   FreeStack
		 38  ReturnNull
		 39        Func    test
		 40     NewLine       9
		 41     FuncExE
		 42       PushC   welcome
		 43       PushP   007D3670      0
		 44       PushV
		 45         SUM       0
		 46       Print
		 47     NewLine      10
		 48  PushPLocal      o1      0
		 49  AssignmentPointer
		 50         New   point
		 51    SetScope
		 52       PushV
		 53  BraceStart
		 54       LoadA       x      0     58
		 55  AssignmentPointer
		 56       PushN   10.000000
		 57  BeforeEqual       0
		 58  SetProperty       0    106
		 59   FreeStack
		 60       LoadA       y      0     64
		 61  AssignmentPointer
		 62       PushN   20.000000
		 63  BeforeEqual       0
		 64  SetProperty       0    141
		 65   FreeStack
		 66       LoadA       z      0     70
		 67  AssignmentPointer
		 68       PushN   30.000000
		 69  BeforeEqual       0
		 70  SetProperty       0    176
		 71   FreeStack
		 72    LoadFunc   ismethod
		 73       LoadA    self      0
		 74       PushV
		 75       PushC   braceend
		 76        Call
		 77  NoOperation
		 78       PushV
		 79       JumpZ      85
		 80    LoadFunc   braceend
		 81        Call
		 82  NoOperation
		 83       PushV
		 84   FreeStack
		 85    BraceEnd
		 86   FreeStack
		 87     NewLine      11
		 88     FuncExE
		 89  PushPLocal      o1      0
		 90       PushV
		 91       Print
		 92     NewLine      13
		 93  ReturnNull
		 94       Class   point  007D8470
		 95    NewLabel
		 96       LoadA       x      0
		 97       PushV
		 98   FreeStack
		 99       LoadA       y      0
		100       PushV
		101   FreeStack
		102       LoadA       z      0
		103       PushV
		104   FreeStack
		105  ReturnNull
		106    LoadFunc   ismethod
		107       LoadA   ring_gettemp_var      0
		108       PushV
		109       PushC    setx
		110        Call       0
		111  NoOperation
		112       PushV
		113       JumpZ     132
		114     NewLine       2
		115       LoadA   ring_gettemp_var      0
		116  LoadMethod    setx
		117       LoadA   ring_settemp_var      0
		118       PushV
		119        Call       0      1
		120  AfterCallMethod
		121       PushV
		122   FreeStack
		123     NewLine       3
		124       LoadA   ring_tempflag_var      0    128
		125  AssignmentPointer
		126       PushN   0.000000
		127  BeforeEqual       0
		128  Assignment       0      0
		129   FreeStack
		130     NewLine       4
		131        Jump     140
		132     NewLine       5
		133       PushP   007D37D8      0    137
		134  AssignmentPointer
		135       PushN   1.000000
		136  BeforeEqual       0
		137  Assignment       0      0
		138   FreeStack
		139     NewLine       6
		140      Return
		141    LoadFunc   ismethod
		142       LoadA   ring_gettemp_var      0
		143       PushV
		144       PushC    sety
		145        Call       0
		146  NoOperation
		147       PushV
		148       JumpZ     167
		149     NewLine       2
		150       LoadA   ring_gettemp_var      0
		151  LoadMethod    sety
		152       LoadA   ring_settemp_var      0
		153       PushV
		154        Call       0      1
		155  AfterCallMethod
		156       PushV
		157   FreeStack
		158     NewLine       3
		159       LoadA   ring_tempflag_var      0    163
		160  AssignmentPointer
		161       PushN   0.000000
		162  BeforeEqual       0
		163  Assignment       0      0
		164   FreeStack
		165     NewLine       4
		166        Jump     175
		167     NewLine       5
		168       PushP   007D37D8      0    172
		169  AssignmentPointer
		170       PushN   1.000000
		171  BeforeEqual       0
		172  Assignment       0      0
		173   FreeStack
		174     NewLine       6
		175      Return
		176    LoadFunc   ismethod
		177       LoadA   ring_gettemp_var      0
		178       PushV
		179       PushC    setz
		180        Call       0
		181  NoOperation
		182       PushV
		183       JumpZ     202
		184     NewLine       2
		185       LoadA   ring_gettemp_var      0
		186  LoadMethod    setz
		187       LoadA   ring_settemp_var      0
		188       PushV
		189        Call       0      1
		190  AfterCallMethod
		191       PushV
		192   FreeStack
		193     NewLine       3
		194       LoadA   ring_tempflag_var      0    198
		195  AssignmentPointer
		196       PushN   0.000000
		197  BeforeEqual       0
		198  Assignment       0      0
		199   FreeStack
		200     NewLine       4
		201        Jump     210
		202     NewLine       5
		203       PushP   007D37D8      0    207
		204  AssignmentPointer
		205       PushN   1.000000
		206  BeforeEqual       0
		207  Assignment       0      0
		208   FreeStack
		209     NewLine       6
		210      Return

	===================================================


CGI Support

edit

Command:

	ring test.ring -cgi

No Run

edit

Command:

	ring test.ring -norun


Printing Instruction Operation Code

edit

Command:

	ring test.ring -ins


Output:

	===================================================

	Operation  : ReturnNull  
	PC         : 1  
	Line Number    : 1  , File test.ring 
	 
	SP (After) : 0  - FuncSP : 0 
	 LineNumber 1 
	===================================================
	.....
	.....
	.....

.. tip:: Output removed from the previous example because it's very large!

Performance

edit

Command:

	ring test.ring -performance

Output:

	===================================================
	Date  : 2015/09/15 Time : 15:56:17
	Clock : 0 
	===================================================
	Hello World
	1
	2
	3
	4
	5
	6
	7
	8
	9
	10
	welcome
	x: 10.000000
	y: 20.000000
	z: 30.000000
	
	===================================================
	Date  : 2015/09/15 Time : 15:56:17
	Clock : 0 
	===================================================



Lessons/Web Development (CGI Library)

Web Development (CGI Library)

edit

In this chapter we will learn about developing Web applications using a CGI Library written in the Ring language.

Ring CGI Hello World Program

edit

The next program is the Hello World program

	#!b:\mahmoud\apps\ring\ring.exe -cgi

	See "content-type : text/html" +nl+nl+
	  "Hello World!" + nl


Hello World Program using the Web Library

edit

We can use the web library to write CGI Web applications quickly

Example (1) :

	#!b:\mahmoud\apps\ring\ring.exe -cgi

	Load "weblib.ring"

	Import System.Web

	New Page 
	{
		Text("Hello World!")
	}

Example (2) :

	#!b:\mahmoud\apps\ring\ring.exe -cgi

	Load "weblib.ring"

	Import System.Web

	WebPage() 
	{
		Text("Hello World!")
	}

.. tip:: the difference between ex. 1 and ex. 2 is using WebPage() function to return the page object instead of creating the object using new statement.

Web Library Features

edit

The next features are provided by the Web library to quickly create web applications.

  • Generate HTML pages using functions
  • Generate HTML pages using objects
  • HTTP Get
  • HTTP Post
  • Files Upload
  • URL Encode
  • Templates
  • CRUD MVC Sample
  • Users Logic & Registration Sample

HTTP Get Example

edit

The Page User Interface

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web
	New Page
	{
	 Title = "Test HTTP Get"
	 divstart([ :style = StyleSizeFull() ] )
	 boxstart()
		text( "Test HTTP GET" )
		newline()
	 boxend() 
	 divstart([ :style = Styledivcenter("600px","550px") + 
			   StyleGradient(21) ])
	 divstart([:style = stylefloatleft() + stylesize("100px","100%") + 
			   stylecolor("black") + stylegradient(58)])
	 formstart("ex5.ring")
		tablestart([ :style = stylesize("65%","90%") + 
				   stylemarginleft("35%") +
				   stylemargintop("30%") ])
		 rowstart([]) 
			cellstart([])
			 text ( "Name : " ) 
			cellend() 
			cellstart([])
			 cTextboxStyle = StyleMarginLeft("5%") + 
					 StyleWidth("250px") + 
					 StyleColor("black") + 
					 StyleBackColor("white")
			 textbox([ :name = "Name", :style = cTextboxStyle ] )  
			cellend()
		 rowend()
		 rowstart([]) 
			cellstart([])
			 text ( "Address : " )  
			cellend()
			cellstart([])
			 textbox([ :name = "Address", :style = cTextboxStyle] ) 
			cellend()
		 rowend()
		 rowstart([]) 
			cellstart([])
			 text ( "Phone : " ) 
			cellend() 
			cellstart([])
			 textbox([ :name = "Phone", :style = cTextboxStyle ]) 
			cellend()
		 rowend()
		 rowstart([]) 
			cellstart([])
			 text ( "Age : " )  
			cellend() 
			cellstart([])
			 textbox([ :name = "Age", :style = cTextboxStyle ]) 
			cellend()
		 rowend()
		 rowstart([]) 
			cellstart([])
			 text ( "City: " )   
			cellend() 
			cellstart([])
			 listbox([ :name = "City", :items = ["Cairo","Riyadh","Jeddah"],
				 :style = stylemarginleft("5%") + stylewidth("400px") ] )
			cellend()
		 rowend()
		 rowstart([]) 
			cellstart([])
			 text ( "Country : " ) 
			cellend() 
			cellstart([])
			 combobox([ :name = "Country",
				 :items = ["Egypt","Saudi Arabia","USA"],
				 :style = stylemarginleft("5%") + 
					 stylewidth("400px")+
					 stylecolor("black")+
					 stylebackcolor("white")+
					 stylefontsize("14px") ])
			cellend()
		 rowend()
		 rowstart([]) 
			cellstart([])
			 text ( "Note : " )    
			cellend() 
			cellstart([])
			 editbox([ :name = "Notes", 
				:style = stylemarginleft("5%") + 
					 stylesize("400px","100px")+
					 stylecolor("black")+
					 stylebackcolor("white") , 
				:value = "write comments here..." ] ) 
			cellend()
		 rowend()
		 rowstart([]) 
			cellstart([])
			cellend()
			cellstart([])
			 submit([ :value = "Send" , :Style = stylemarginleft("5%") ])
			cellend()
		 rowend()   
		tableend()
	 formend()
	 divend()
	 divend()
	 divend()
	}

Screen Shot:

 

The Response

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web
	New Page
	{
	 divstart([ :style = styledivcenter("800px","500px") ])
	 boxstart()
		text ( "HTTP GET Response" ) newline()
	 boxend()
	 divstart([ :style = stylefloatleft()+stylewidth("10%")+
			   stylecolor("black")+stylegradient(58) ])
		newline()
		text ( "Name : "  )
		newline() newline()
		text ( "Address : " )
		newline() newline()
		text ( "Phone : "  )
		newline() newline()
		text ( "Age : "  )
		newline() newline()
		text ( "City : "  )
		newline() newline()
		text ( "Country : "  )
		newline() newline()
		text ( "Note : "  )
		newline() newline()
	 divend()
	 divstart([ :style = stylefloatleft()+stylewidth("90%")+
			   stylecolor("black")+stylegradient(47) ])
		divstart([ :style = stylefloatleft() + stylewidth("1%") ])
		 newline()
		divend()
		divstart([ :style = stylefloatleft() + stylewidth("95%") ])
		 newline()
		 text ( aPageVars["Name"] )
		 newline() newline()
		 text ( aPageVars["Address"] )
		 newline() newline()
		 text ( aPageVars["Phone"] )
		 newline() newline()
		 text ( aPageVars["Age"] )
		 newline() newline()
		 text ( aPageVars["City"] )
		 newline() newline()
		 text (aPageVars["Country"] )
		 newline() newline()
		 text ( aPageVars["Notes"] )
		 newline() newline()
		divend()
	 divend()
	 divend()
	}

Screen Shot:

 


HTTP POST Example

edit

The Page User Interface

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web
	New Page 
	{
		boxstart()
			text( "Post Test")
			newline()
		boxend()
		divstart([ :style=StyleFloatLeft()+StyleWidth("100px") ])
			newline()
			text( "Number1 : " ) 	newline() newline()
			text( "Number2 : " ) 	newline() newline()
		divend()
		formpost("ex7.ring")
			divstart([ :style = styleFloatLeft()+StyleWidth("200px") ])
				newline()
				textbox([ :name = "Number1" ]) 	newline() newline()
				textbox([ :name = "Number2" ]) 	newline() newline()
				submit([ :value = "Send" ] )
			divend()
		formend()
	}


Screen Shot:

 

The Response

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web
	New Page 
	{
		boxstart()
			text( "Post Result" )
			newline()
		boxend()
		divstart([ :style = styleFloatLeft()+styleWidth("200px") ])
			newline()
			text( "Number1 : " + aPageVars["Number1"] ) 	
			newline() newline()
			text( "Number2 : " + aPageVars["Number2"] ) 	
			newline() newline()
			text( "Sum : " + (0 + aPageVars["Number1"] + aPageVars["Number2"] ) )
			newline()
		divend()		
	}

Screen Shot:

 

Upload Files

edit

The Page User Interface

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web
	New page 
	{
		boxstart()
			text( "Upload File" )
			newline()
		boxend()
		for x = 1 to 3 newline() next
		formupload("ex9.ring")		
			text( "Customer Name : " )
			textbox([ :name = "custname" ]) 	
			newline() newline()		
			divstart([ :style = styleFloatLeft() + styleWidth("90px") ])
				uploadfile("file") newline() newline()
				uploadfile("file2") newline() newline()
				submit([ :value = "Send" ])
			divend()		
		formend()
	}

Screen Shot:

 

The Response

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	cUploadPath = "C:/Apache2.2/htdocs/ringapp/upload/"
	cUploadFolder = "/ringapp/upload/"

	New page 
	{
		boxstart()
			text( "Upload Result" )
			newline()
		boxend()			
		newline() 
		divstart([ :style= styleFloatLeft() + styleWidth("100px") ])
			text( "Name : " + aPageVars["custname"] )
			newline()
		divend()
		if aPageVars["file"] != char(13)
			getuploadedfile(self,"file")
		ok
		if aPageVars["file2"] != char(13)
			getuploadedfile(self,"file2")
		ok
	}	

	Func getuploadedfile oObj,cFile
		# here we use object.property 
		# instead of object { } to avoid executing braceend method
		cFileName = cUploadPath + oObj.getfilename(aPageVars,cFile)
		write(cFileName,aPageVars[cFile])
		system("chmod a+x "+cFileName)
		oObj.newline() 
		oObj.text( "File "+cFileName+ " Uploaded ..." ) 
		oObj.newline()
		imageURL = cUploadFolder+oObj.getfilename(aPageVars,cFile)
		oObj.link([ :url = imageURL, :title = "Download" ]) 
		oObj.newline()
		oObj.image( [ :url = imageURL , :alt = :image ] )
		oObj.newline()

Screen Shot:

 


Cookies

edit

The Page User Interface

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	New page 
	{
		boxstart()
			text( "Cookie Test" )
			newline()
		boxend()
		newline()
		link([ :url = "ex11.ring", :title = "Use Cookies" ]) 	
		cookie("custname","Mahmoud Fayed")
		cookie("custage",28)	
	}

Screen Shot:

 

The Response

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	New Page 
	{
		boxstart()
			text( "Cookies Values" )
			newline()
		boxend()
		link([ :url = "ex10.ring", :title = "back" ]) 			
		newline() 
		divstart([:style="float:left;width:200px"])
			text( "Name : " + aPageVars["custname"] )
			newline()
			text( "Age : " + aPageVars["custage"] )
			newline()
		divend()
	}

Screen Shot:

 

URL Encode

edit

The Page User Interface

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	New Page 
	{
		boxstart()
			text( "URLEncode" )
			newline()
		boxend()
		link([ :url = "ex5.ring?Name="+URLEncode("-*{Mahmoud}*-")+
			   "&Address=Egypt&Phone=123456&Age=28&Notes=Programmer", 
			   :title = "Test URL Encode" ])
	}

Screen Shot:

 


Screen Shot:

 


Templates

edit

Using Templates we can write Ring code inside HTML files

Syntax:

	<%= Ring Expression %>
	<% Ring Statements %>

The HTML Code

	<h1>Listing Numbers</h1> 
	<table>
	 <tr>
	  <th> <%= myheader.cColumn1 %> </th>
	  <th> <%= myheader.cColumn2 %> </th>
	  <th></th>
	  <th></th>
	  <th></th>
	 </tr>
	<% for x in aNumbers %> 
	 <tr>
	  <td> <%= x.nValue %> </td>
	  <td> <%= x.nSquare %> </td>
	 </tr>
	<% next %>
	</table>

The Ring Code

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	New NumbersController { start() }

	Class NumbersController

		MyHeader aNumbers		

		Func Start

			MyHeader = New Header
			{
				cColumn1 = "Number" cColumn2 = "Square"
			}

			aNumbers = list(20)

			for x = 1 to len(aNumbers)
				aNumbers[x] = new number
				{
					nValue = x  nSquare = x*x
				}
			next	 

			cTemp = Template("mynumbers.html",self)

			New Page 
			{ 			
				boxstart()
					text( "Test Templates" ) 			
					newline()
				boxend()
				html(cTemp) 
			} 

	Class Header cColumn1 cColumn2
	Class Number nValue  nSquare

Screen Shot:

 


HTML Special Characters

edit

The text() function display HTML special characters.

If you want to write html code, use the html() function.

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	New Page
	{
		boxstart()
			text("HTML Special Characters")
			newline()
		boxend()
		text('
			<html>
				<body>
					<p> "hello world" </p>
				</body>
			</html>
		')
	}

Screen Shot:

 


Hash Functions

edit

The Page User Interface

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	New Page 
	{
		boxstart()
			text( "Hash Test")
			newline()
		boxend()
		divstart([ :style = StyleFloatLeft() + StyleWidth("100px") ])
			newline()
			text( "Value : " ) 	
			newline() newline()
		divend()
		formpost("ex16.ring")
			divstart([ :style = StyleFloatLeft() + StyleWidth("300px") ])
				newline()
				textbox([ :name = "Value" ]) 	
				newline() newline()
				submit([ :value = "Send" ])
			divend()
		formend()
	}

Screen Shot:

 

The Response

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	New Page 
	{
		boxstart()
			text( "Hash Result" )
			newline()
		boxend()
		divstart([ :style = styleFloatLeft() + styleWidth("100%") ])
			newline()
			text( "Value : " + aPageVars["Value"] ) 	
			newline()
			text( "MD5 : "  + MD5(aPageVars["Value"]) ) 	
			newline()
			text( "SHA1 : "  + SHA1(aPageVars["Value"]) )
			newline()
			text( "SHA256 : " + SHA256(aPageVars["Value"]) )
			newline()
			text( "SHA224 : " + SHA224(aPageVars["Value"]) )
			newline()
			text( "SHA384 : " + SHA384(aPageVars["Value"]) )
			newline()
			text( "SHA512 : " + SHA512(aPageVars["Value"]) )
			newline()
		divend()
	}

Screen Shot:

 


Random Image

edit
	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	cUploadPath = "C:/Apache2.2/htdocs/ringapp/upload/"

	New Page 
	{
		boxstart()
			text( "Random Test")
			newline()
		boxend()	
		divstart([ :style = styleFloatLeft() + styleWidth("400px") ])
			newline()
			aList = dir(cUploadPath)
			if len(aList) > 0
				nIndex = random(len(aList)) 
				if nindex = 0 nIndex = 1 ok
				cItem = "upload/" + aList[nIndex][1]
				newline()
				image( [ :url = cItem , :alt = :image ] )
			else
				text("No images!") newline()
			ok
		divend()
	}

Screen Shot:

 

HTML Lists

edit

The next example print a list contains numbers from 1 to 10

Then print a list from Ring List.

Finally we have a list of buttons and when we press on a button we get a message contains the clicked button number.

To start the list we uses the ulstart() function.

To end the list we uses the ulend() function.

We uses listart() and liend() to determine the list item.

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	Func Main
		New Page 
		{	 
			ulstart([])
				for x = 1 to 10
					listart([])
						text(x)
					liend()
				next
			ulend()	 
			list2ul(["one","two","three","four","five"])
			ulstart([])
				for x = 1 to 10
					listart([])
						cFuncName = "btn"+x+"()"
						button([ :onclick = cFuncName , :value = x])
						script(scriptfuncalert(cFuncName,string(x)))
					liend()
				next
			ulend()
		}

Screen Shot:

 


HTML Tables

edit

In this example we will learn how to generate HTML tables using the tablestart(), tableend(), rowstart(), rowend() ,headerstart(), headerend(), cellstart() and cellend() functions.

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	Func Main
		New Page
		{
			divstart([ :style = styledivcenter("400px","500px") ] )
				style(styletable() + styletablerows("t01"))
				tablestart([ :id = :t01 , :style = stylewidth("100%") ])
					rowstart([]) 
						headerstart([]) text("Number") headerend()
						headerstart([]) text("square") headerend()
					rowend() 
					for x = 1 to 10
						rowstart([])
							cellstart([]) text(x) 	cellend()
							cellstart([]) text(x*x) cellend()
						rowend()
					next
				tableend()
			divend()
		}

Screen Shot:

 

Gradient

edit

In this example we will learn how to use the StyleGradient() function.

The function takes the style number as input (range from 1 to 60).

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	Func Main
		New Page
		{
			boxstart()
				text("StyleGradient() Function")
			boxend()			 
			for x = 1 to 60				
				divstart([ :id = x , :align = "center" , 
					  :style = stylefloatleft() +
						  stylesize(string(100/60*6)+"%","50px") +
						  stylegradient(x) ])
					h3(x)
				divend()					 
			next
		}

Screen Shot:

 

Generating Pages using Objects

edit

Instead of using functions/methods to generate HTML pages, we can use an object for each element in the page.

This choice means more beautiful code but slower.

The fastest method is to print HTML code directly, then using functions then using templates then using objects (slower).

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	Func Main

	 WebPage() 
	 {
		Title = "Using objects to create the Web Page content"
		h1 { text("welcome") }
		link 
		{ 
		 Title = "Google" 
		 Link = "http://www.google.com"
		} 
		div 
		{
		 id = "div1"
		 style = stylegradient(30) + stylesize("50%","50%")
		 text("Outer Div")
		 div 
		 {
			id = "div2"
			color = "white"
			backgroundcolor = "green"
			width = "50%"
			height = "50%"
			marginleft = "5%"
			margintop = "5%"
			text("Inner Div")
		 }
		}
		div
		{
		 id = "div3"
		 color = "black"
		 backgroundcolor = "silver"
		 width = "100%"
		 height = "100%"
		 text("Form")
		 form
		 {
			method = "POST"
			Action = "helloworld.ring"
			Table
			{ 
			 style = stylewidth("100%") + stylegradient(24)   
			 TR 
			 { 
				TD { WIDTH="10%" text("Name : " ) }
				TD { Input { type = "text" } }
			 }
			 TR
			 {
				TD { WIDTH="10%" text("Email : " ) }
				TD { Input { type = "text" } }
			 }
			 TR 
			 {
				TD { WIDTH="10%" text("Password : " ) }
				TD { Input { type = "password" } }
			 }
			 TR
			 {
			 
				TD { WIDTH="10%" text("Notes") }
				TD { TextArea { width="100%" rows = 10 cols = 10 
				  		text("type text here...") } }
			 }
			 TR
			 {
				TD { WIDTH="10%" text("Gender") }
				TD { 
				 select
				  {
					 width = "100%"
					 option { text("Male") } 
					 option { text("Female") } 
				  }
				}
			 }
			 TR
			 {
				TD {  WIDTH="10%" text("Role") }
				TD 
				{
				 select
				 { 
					 multiple = "multiple"
					 width  = "100%"
					 option { text("student") } 
					 option { text("admin") } 
				  }
				}
			 }
			}
			Input { type = "submit" value = "send" }
			Image { src="upload/profile1.jpg" alt="profile"}
			Input { type = "checkbox" value = "Old Member"} text("old member")
			Input { type = "range" min=1 max=100}
			Input { type = "number" min=1 max=100}
			Input { type = "radio" color="black" name="one" 
				value = "one"} text("one")
		 }
		}
		div
		{
		 color = "white"
		 backgroundcolor = "blue"
		 width = "100%"   
		 UL
		 {
			LI { TEXT("ONE") }
			LI { TEXT("TWO") }
			LI { TEXT("THREE") }
		 }
		}
		div 
		{
		 audio
		 {
			src = "horse.ogg"
			type = "audio/ogg"
		 }

		 video
		 {
			 width = 320
			 height = 240
			 src = "movie.mp4"
			 type = "video/mp4" 
		 }

		 Input
		 {
			type = "color"
			value = "#ff0000"
			onchange = "clickColor(0, -1, -1, 5)"
		 }
		}
	 }

Screen Shot:

 

 


Using Bootstrap Library using Functions

edit

The next example uses the Bootstrap JavaScript Library when generating the HTML page.

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	Func Main
	 new BootstrapPage {
		divstart([ :class = "container" ])
		  divstart([ :class = "jumbotron" ])
			h1("Bootstrap Page")
		 divend() 
		 divstart([ :class = :row ]) 
			divstart([ :class = "col-sm-4" ])
			 h3("Welcome to the Ring programming language")
			 p([ :text = "Using a scripting language is very fun!" ])
			divend()
			divstart([ :class = "col-sm-4" ])
			 h3("Welcome to the Ring programming language")
			 p([ :text = "using a scripting language is very fun!" ])
			divend()
			divstart([ :class = "col-sm-4" ])
			 h3("Welcome to the Ring programming language")
			 p([ :text = "using a scripting language is very fun!" ])
			divend()
		 divend()  
		divend()
	 }


Screen Shot:

 

Using Bootstrap Library using Objects

edit

The next example uses the Bootstrap JavaScript Library when generating the HTML page.

Instead of using functions to generate the HTML elements, we will use objects.

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Import System.Web

	Func Main
	 BootStrapWebPage()
	 {
		div
		{
		 classname = :container
		 div
		 {
			classname = :jumbotron
			H1 {  text("Bootstrap Page")  }
		 }
		 div
		 {
			classname = :row
			for x = 1 to 3
			 div
			 {
				classname = "col-sm-4"
				H3 { html("Welcome to the Ring programming language") }
				P { html("Using a scripting language is very fun!") }
			 }
			next 
		 }
		 div
		 {
			classname = :row
			div
			{
			 classname = "col-sm-4"
			 Button
			 {      
				classname = "btn btn-info btn-lg"
				datatoggle= "modal"
				datatarget = "#myModal"
				text("Open Large Modal")
			 }     
			}
			div
			{
			 classname = "col-sm-4"
			 Button { classname = "btn btn-default btn-lg" text("default") }
			 Button { classname = "btn btn-primary btn-md" text("primary") }
			 Button { classname = "btn btn-sucess btn-sm" text("sucess") }
			 Button { classname = "btn btn-info btn-xs"  text("info") }
			 Button { classname = "btn btn-warning"    text("warning") }
			 Button { classname = "btn btn-danger"     text("danger") }
			 Button { classname = "btn btn-link"      text("link") }
			}
			div
			{
			 classname = "col-sm-4"
			 Button { classname = "btn btn-default btn-block" text("default") }
			 Button { classname = "btn btn-primary btn-block" text("primary") }
			 Button { classname = "btn btn-sucess btn-block" text("sucess") }
			 Button { classname = "btn btn-info btn-block"  text("info") }
			 Button { classname = "btn btn-warning btn-block" text("warning") }
			 Button { classname = "btn btn-danger btn-block" text("danger") }
			 Button { classname = "btn btn-link btn-block"  text("link") }
			}
			div
			{
			 classname = "col-sm-4"
			 div { classname = "btn-group" 
				button { classname="btn btn-primary" text("one") }
				button { classname="btn btn-primary" text("two") }
				button { classname="btn btn-primary" text("three") }
			 }
			}
			div
			{
			 classname = "col-sm-4"
			 div { classname = "btn-group btn-group-lg" 
				button { classname="btn btn-primary" text("one") }
				button { classname="btn btn-primary" text("two") }
				button { classname="btn btn-primary" text("three") }
			 }
			}
			div
			{
			 classname = "col-sm-4"
			 div { 
				classname = "btn-group-vertical btn-group-lg" 
				button { classname="btn btn-primary" text("one") }
				button { classname="btn btn-primary" text("two") }
				button { classname="btn btn-primary" text("three") }
			 }
			}
		 } 
		 div { classname="modal fade" id="myModal" role="dialog"   
			div { classname = "modal-dialog modal-lg"
			 div { classname="modal-content" 
				div { classname="modal-header"
				 button { classname="close" datadismiss="modal"
					html("&times")
				 }
				 h4 { classname="modal-title"
					text("Modal Header")
				 }
				}
				div { classname = "modal-body" 
				 p { text("This is a large model.") }
				}
				div { classname="modal-footer"
				 button { classname = "btn btn-default" datadismiss="modal"
					text("close")
				 }
				}
			 }
			}
		 }
		} 
	 }

Screen Shot:

 

CRUD Example using MVC

edit

The next example uses the weblib.ring & datalib.ring.

The datalib.ring contains classes for creating database applications using MVC pattern.

In this example we create an object from the SalaryController class then call the Routing method.

We define the website variable to contains the basic url of the page.

When we create the SalaryModel class from the ModelBase class, the salary table will be opened and the columns data will be defined as attributes in the model class.

The SalaryView class create an object from the SalaryLanguageEnglish class to be used for translation.

The method AddFuncScript is used to call the form for adding/modifying record data.

The method FormViewContent is used to determine the controls in the form when we add or modify a record.

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Load "datalib.ring"
	Import System.Web

	website = "ex24.ring"

	New SalaryController { Routing() }

	Class SalaryModel from ModelBase

	Class SalaryController From ControllerBase

	Class SalaryView From ViewBase

	 oLanguage = new SalaryLanguageEnglish

	 Func AddFuncScript oPage,oController
		return  oPage.scriptfuncajax("myadd",oController.cMainURL+
			 oController.cOperation+"=add","mysubpage")

	 Func FormViewContent oController,oTranslation,oPage
		return [
				[ oTranslation.aColumnsTitles[2], "textbox", "name",
				 oController.oModel.Name, oPage.stylewidth("100%")  ],
				[ oTranslation.aColumnsTitles[3], "textbox", "salary",
				 oController.oModel.Salary, oPage.stylewidth("50%") ]
			  ]

	Class SalaryLanguageEnglish
	 cTitle = "Salary Table"
	 cBack = "back"
	 aColumnsTitles = ["ID","Name","Salary"]
	 cOptions = "Options"
	 cSearch = "Search"
	 comboitems = ["Select Option...","Edit","Delete"]
	 cAddRecord = "Add Record"
	 cEditRecord = "Edit Record"
	 cRecordDeleted = "Record Deleted!"
	 aMovePages = ["First","Prev","Next","Last"]
	 cPage = "Page"
	 cOf = "of"
	 cRecordsCount = "Records Count"
	 cSave = "Save"
	 temp = new page
	 cTextAlign = temp.StyleTextRight()
	 cNoRecords = "No records!"

Screen Shot:

 

 

Users registration and Login

edit

We have the users classes (Model, View & Controller) to deal with the users data like username & email.

The next code is stored in ex25_users.ring

	Class UsersModel from ModelBase
	 cSearchColumn = "username"

	Class UsersController From ControllerBase
	 aColumnsNames = ["id","username","email"]

	 Func UpdateRecord
		oModel.id = aPageVars[cRecID]
		oModel.updatecolumn("username", aPageVars[:username] )
		oModel.updatecolumn("email", aPageVars[:email] )
		oView.UpdateView(self)

	Class UsersView from ViewBase

	 oLanguage = new UsersLanguageEnglish

	 Func AddFuncScript oPage,oController
		return  oPage.scriptfunc("myadd",oPage.scriptredirection("ex26.ring"))

	 Func FormViewContent oController,oTranslation,oPage
		return [
				[oTranslation.aColumnsTitles[2],"textbox","username",
				oController.oModel.UserName,oPage.stylewidth("100%")],
				[oTranslation.aColumnsTitles[3],"textbox","email",
				oController.oModel.Email,oPage.stylewidth("50%")]
			  ]

	Class UsersLanguageEnglish
	 cTitle = "Users Table"
	 cBack = "back"
	 aColumnsTitles = ["ID","User Name","Email"]
	 cOptions = "Options"
	 cSearch = "Search"
	 comboitems = ["Select Option...","Edit","Delete"]
	 cAddRecord = "Add Record"
	 cEditRecord = "Edit Record"
	 cRecordDeleted = "Record Deleted!"
	 aMovePages = ["First","Prev","Next","Last"]
	 cPage = "Page"
	 cOf = "of"
	 cRecordsCount = "Records Count"
	 cSave = "Save"
	 temp = new page
	 cTextAlign = temp.StyleTextRight()
	 cNoRecords = "No records!"

In the file ex25.ring we load ex25_users.ring then create an object from UsersController class.

Using the created object, we call the routing method.

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Load "datalib.ring"
	Load "ex25_users.ring"

	Import System.Web
	website = "ex25.ring"
	New UsersController { Routing() }

Screen Shot:

 


See the next code for the registration page

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Load "datalib.ring"
	Import System.Web

	website = "ex26.ring"

	new page {
	 boxstart()
		text( "Register")
		newline()
	 boxend()
	 divstart([:style = stylegradient(6) + stylesize("100%","95%") ])
	 link([ :url = website, :title = "back" , :style = stylecolor("white")])  
	 newline()
	 divstart([ :style= styledivcenter("500","160") + stylegradient(52) ])  
	 formpost("ex27.ring")
		tablestart([ :Style =  stylemarginleft("2%") + stylemargintop("2%") +
					 stylewidth("90%") ])
		 rowstart([])
			cellstart([:style = stylewidth("20%") + styleheight(30)])
			 text("User Name")
			cellend()
			cellstart([ :style = stylewidth("80%") ])
			 textbox([:name = "username", :style = stylewidth("100%")])
			cellend()
		 rowend()
		 rowstart([])
			cellstart([ :Style = styleheight(30)])
			 text("Password")
			cellend()
			cellstart([])
			 textbox([:name = "password" , :type = "password"])
			cellend()
		 rowend()
		 rowstart([])
			cellstart([ :style = styleheight(30)])
			 text("Email")
			cellend()
			cellstart([])
			 textbox([:name = "email" , :style = stylewidth("100%")])
			cellend()
		 rowend()
		 rowstart([])
			cellstart([ :style = styleheight(30)])
			cellend()
			cellstart([ :style = styleheight(30)])
			 submit([:value = "Register" ])
			cellend()
		 rowend()
		tableend()
	 formend()
	 divend()
	 divend()
	}

Screen Shot:

 

The Registration response

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Load "datalib.ring"
	Load "ex25_users.ring"

	Import System.Web

	oUser = new UsersModel
	oUser.Connect()
	if oUser.findwith("username",aPageVars["username"])
		new page {
			text("The user name is already registered")
		}
		return
	ok
	if oUser.findwith("email",aPageVars["email"])
		new page {
			text("This email is already registered")
		}
		return
	ok

	aPageVars["salt"] = str2hex(RandBytes(32))
	aPageVars["pwhash"] = sha256(aPagevars["password"]+aPageVars["salt"])
	aPageVars["sessionid"] = str2hex(randbytes(32))
	oUser.Insert()
	new page {
		cookie("sessionid",aPageVars["sessionid"])
		text("New User Created!")
		newline()
		text("User Name : " + aPageVars["username"])
		newline()
	}
	oUser.Disconnect()

See the next code for the Login page

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Load "datalib.ring"

	Import System.Web

	website = "ex28.ring"

	new page {
	 boxstart()
		text( "Login")
		newline()
	 boxend()
	 divstart([:style = stylegradient(6) + stylesize("100%","95%") ])
	 link([ :url = website, :title = "back" , :style = stylecolor("white")])  
	 newline()
	 divstart([ :style= styledivcenter("500","130") + stylegradient(52) ])  
	 formpost("ex29.ring")
		tablestart([ :Style =  stylemarginleft("2%") + stylemargintop("2%") +
					stylewidth("90%") ])
		 rowstart([])
			cellstart([:style = stylewidth("20%") + styleheight(30)])
			 text("User Name")
			cellend()
			cellstart([ :style = stylewidth("80%") ])
			 textbox([:name = "username", :style = stylewidth("100%")])
			cellend()
		 rowend()
		 rowstart([])
			cellstart([ :style = styleheight(30)])
			 text("Password")
			cellend()
			cellstart([])
			 textbox([:name = "password" , :type = "password"])
			cellend()
		 rowend()
		 rowstart([])
			cellstart([ :style = styleheight(30) ])
			cellend()
			cellstart([])
			 submit([:value = "Login" ])
			cellend()
		 rowend()
		tableend()
	 formend()
	 divend()
	 divend()
	}

Screen Shot:

 

The response page

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Load "datalib.ring"
	Load "ex25_users.ring"

	Import System.Web

	oUser = new UsersModel
	oUser.Connect()
	lResult = oUser.FindWith("username",aPageVars["username"])
	new page {
		if lResult
			if sha256(aPagevars["password"]+oUser.Salt) = oUser.pwhash
				text ("Correct Password!")
				aPageVars["sessionid"] = str2hex(randbytes(32))
				oUser.UpdateColumn("sessionid",aPageVars["sessionid"])
				cookie("sessionid",aPageVars["sessionid"])
			else
				text ("Bad password!")
			ok
		else
			text("Bad User Name!")
		ok
	}
	oUser.Disconnect()

The next code for checking if the user needs to login or not

	#!b:\mahmoud\apps\ring\ring.exe -cgi
	Load "weblib.ring"
	Load "datalib.ring"
	Load "ex25_users.ring"

	Import System.Web

	oUser = new UsersModel
	oUser.Connect()
	lResult = oUser.FindWith("sessionid",aPageVars["sessionid"])
	new page {
		if lResult
			text("User Name : " + oUser.username )
		else
			text("Please Login First!")
		ok			
	}
	oUser.Disconnect()

Database, ModelBase & ControllerBase classes

edit

In this section we will see some code from datalib.ring

The next code presents the Database, ModelBase & ControllerBase classes

	Import System.Web

	Class Database

	 cServer = "localhost"
	 cUserName = "root"
	 cPassword = "root"
	 cDatabase = "mahdb"

	 Func Connect

		con = mysql_init() 
		mysql_connect(con, cServer, cUserName, cPassWord,cDatabase)

	 Func Disconnect

		mysql_close(con)

	 Func Query cQuery

		mysql_query(con,cQuery)

	 Func QueryResult

		return mysql_result(con)

	 Func QueryResultWithColumns
		# return columns names + query result
		return mysql_result2(con)

	 Func QueryValue
		aResult = mysql_result(con)
		if islist(aResult) and len(aResult) >= 1
		 aResult = aResult[1]
		 if len(aResult) >= 1
			return aResult[1]
		 ok
		ok
		return 0

	 Func EscapeString x
		if isstring(x)
		 return MySQL_Escape_String(con,x)
		else
		 return MySQL_Escape_String(con,string(x))
		ok

	 Private
		con = NULL

	Class ModelBase from Database

	 cTableName = ""
	 cSearchColumn = "name"
	 aColumns = []
	 aQueryResult = []
	 ID = 0

	 # set table name from class name
	 classname = lower(classname(self))
	 if right(classname,5) = :model
		cTablename = left(classname,len(classname)-5)
	 ok

	 Func Insert 

		cValues = ""
		for x in aColumns
		 cValues += "'" + EscapeString(aPageVars[x]) + "',"
		Next
		cValues = left(cValues,len(cValues)-1) # remove last comma  
		cColumns = ""
		for x in aColumns
		 cColumns += x + ","
		next
		cColumns = left(cColumns,len(cColumns)-1)  
		query("insert into " + cTableName + "("+cColumns+") values (" + 
			 cValues + ")" )

	 Func Update nID

		cStr = ""
		for x in aColumns
		 cStr += x + " = '" + EscapeString(aPageVars[x]) + "' , " 
		# the space after comma is necessary
		Next
		cStr = left(cStr,len(cStr)-2)   
		query("update " + cTableName + " set " + cStr + " where id = " + nID )

	 Func UpdateColumn cColumn,cValue
		query("update " + cTableName + " set " + cColumn + " = '" + 
	    EscapeString(cValue) + "' where id = " + self.ID )


	 Func Count cValue

		query("SELECT count(*) FROM " + cTableName +
			 " where "+cSearchColumn+" like '" + EscapeString(cValue) + "%'")
		return queryValue()

	 Func Read nStart,nRecordsPerPage

		query("SELECT * FROM "+ cTableName+" limit " + EscapeString(nStart) + "," +
	    EscapeString(nRecordsPerPage) )
		aQueryResult = queryResult()

	 Func Search cValue,nStart,nRecordsPerPage

		query("SELECT * FROM "+ cTableName+" where "+cSearchColumn+" like '" +
	    EscapeString(cValue) + "%'" +
		 " limit " + EscapeString(nStart) + "," + EscapeString(nRecordsPerPage) )
		aQueryResult = queryResult()

	 Func Find nID

		query("select * from " + cTableName + " where id = " + EscapeString(nID) )
		aResult = queryResult()[1]
		# move the result from the array to the object attributes
		ID = nID
		cCode = ""
		for x = 2 to len(aResult)
		 cCode += aColumns[x-1] + " = hex2str('" + str2hex(aResult[x]) + "')" + nl
		next
		eval(cCode)

	 Func FindWith cColumn,cValue

		query("select * from " + cTableName + " where "+cColumn+" = '" + 
	    EscapeString(cValue) + "'" )
		aResult = queryResult()
		if len(aResult) > 0
		 aResult = aResult[1]
		else
		 return 0
		ok
		# move the result from the array to the object attributes
		ID = aResult[1]
		cCode = ""
		for x = 2 to len(aResult)
		 cCode += aColumns[x-1] + " = hex2str('" + str2hex(aResult[x]) + "')" + nl
		next
		eval(cCode)
		return 1

	 Func Delete ID

		query("delete from " + cTableName + " where id = " + EscapeString(ID) )

	 Func Clear

		cCode = ""
		for x in aColumns
		 cCode += x + ' = ""' + nl
		next
		eval(cCode)

	 Func LoadModel

		# create the columns array
		query("SELECT * FROM "+ cTableName + " limit 0,1")
		aQueryResult = QueryResultWithColumns()[1]
		for x = 2 to len(aQueryResult)
		 aColumns + lower(trim(aQueryResult[x]))
		next

		# create attribute for each column
		for x in aColumns
		 addattribute(self,x)
		next

	 Func Connect

		Super.Connect()
		if nLoadModel = 0
		 nLoadModel = 1
		 LoadModel()
		ok

	 private

		nLoadModel = 0


	Class ControllerBase
	 
	 nRecordsPerPage = 5
	 nRecordsCount = 0
	 nPagesCount = 0
	 nActivePage = 0

	 # Dynamic creation of oView = new tablenameView and oModel = new tablename.Model
	 classname = lower(classname(self))
	 if right(classname,10) = :controller
		tablename = left(classname,len(classname)-10)
		cCode = "oView = new " + tablename+"View" + nl
		cCode += "oModel = new " + tablename+"Model" + nl
		eval(cCode)
		oModel.connect()
	 ok

	 cSearchName = "searchname"
	 cPart = "part"
	 cPageError = "The page number is not correct"
	 cLast = "last"
	 cOperation = "operation"
	 cRecID = "recid"

	 aColumnsNames = ["id"]
	 for t in oModel.aColumns
		aColumnsNames + t
	 next

	 cMainURL = website + "?"

	 func Routing

		switch   aPageVars[cOperation]
		on NULL   showtable()
		on :add   addrecord()
		on :save  saverecord()
		on :delete deleterecord()
		on :edit  editrecord()
		on :update updaterecord()
		off

	 func ShowTable

		nRecordsCount = oModel.Count( aPageVars[cSearchName] )

		nPagesCount = ceil(nRecordsCount / nRecordsPerPage)

		if aPageVars[cPart] = cLast
		 aPageVars[cPart] = string(nPagesCount)
		ok

		nActivePage = number(aPageVars[cPart])
		if nActivePage = 0 nActivePage = 1 ok  

		if ( nActivePage > nPagesCount ) and nRecordsCount > 0
		 ErrorMsg(cPageError)
		 return
		ok

		nStart = (nActivePage-1)*nRecordsPerPage

		if aPageVars[cSearchName] = NULL
		 oModel.Read( nStart,nRecordsPerPage )
		else
		 oModel.Search( aPageVars[cSearchName],nStart,nRecordsPerPage )
		ok

		oView.GridView(self)

	 func AddRecord

		oModel.clear()
		oView.FormViewAdd(Self,:save,false) # false mean don't include record id

	 func SaveRecord

		oModel.Insert()
		oView.SaveView(self)

	 func EditRecord

		oModel.Find( aPageVars[cRecID] )
		oView.FormViewEdit(Self,:update,true) # true mean include record id

	 func UpdateRecord

		oModel.update( aPageVars[cRecID] )
		oView.UpdateView(self)

	 func DeleteRecord

		oModel.Delete( aPageVars[cRecID] )
		oView.DeleteView()

	 func braceend

		oModel.Disconnect()

WebLib API

edit

In this section we will see the web library functions, classes and methods.

=====================	=============	=====================================================================
Function        Parameters   Description
=====================	=============	=====================================================================
LoadVars        None      Save the request parameters and cookies to aPageVars List
WebPage         None      Create new object from the WebPage Class
BootStrapWebPage    None      Create new object from the BootStrapWebPage Class
HTMLSpecialChars    cString     Encode Special characters to HTML equivalent
Template        cFile,oObject  Execute Ring Code in cFile after accessing oObject using {}
Alert          cMessage    Generate HTML Web Page that display cMessage using JavaScript Alert()
HTML2PDF        cString     Generate and Display PDF File from HTML String (cString)
=====================	=============	=====================================================================

The Package System.Web contains the next classes

=====================	========================================================	
   Class Name     Description
=====================	========================================================	
Application       Contains methods for Encoding, Decoding, Cookies & More.
Page          Contains methods to generate HTML pages.
ScriptFunctions     Contains methods to generate some JavaScript Functions.
StyleFunctions     Contains methods to generate CSS.
PageBuffer       Generate HTML Page in memory (don't print the output).
HTML2PDF        Generate PDF File from HTML code.
BootStrapPage      Using BootStrap Library.
WebPage         Generate page using objects for each element.
BootStrapWebPage    Generate page using objects, using BootStrap Library.
ObjsBase        Parent Class for page objects.
NewObjectsFunctions   Methods to create new objects in the page or element.
H1           Wraps HTML H1.
H2           Wraps HTML H2.
H3           Wraps HTML H3.
H4           Wraps HTML H4.	
H5           Wraps HTML H5.
H6           Wraps HTML H6.	
P            Wraps HTML P.
Link          Wraps HTML link.
NewLine         Wraps HTML NewLine.
Div           Wraps HTML Div.
Form          Wraps HTML Form.
Input          Wraps HTML Input.	
TextArea        Wraps HTML TextArea.
Select         Wraps HTML Select.
Option         Wraps HTML Option.
Image          Wraps HTML Image.
UL           Wraps HTML UL.
LI           Wraps HTML LI.
Table          Wraps HTML Table.
TR           Wraps HTML TR.
TD           Wraps HTML TD.
TH           Wraps HTML TH.
Audio          Wraps HTML Audio.
Video          Wraps HTML Video.
Nav           Wraps HTML Nav.
Span          Wraps HTML Span.
Button         Wraps HTML Button.
=====================	========================================================

Application Class

edit
=====================	=======================================	=====================================================================
Method         Parameters               Description
=====================	=======================================	=====================================================================
DecodeString      cString                 Decode request parameters
Decode         cString                 Decode multipart/form-data
GetFileName       aArray,cVar               Get File Name in aArray using cVar 
SetCookie        name,value,expires,path,domain,secure  Set Cookie 
Cookie         name,value               Set Cookie using name and value only
GetCookies       None                  Get Cookies
URLEncode        cString                 URL Encode 
ScriptLibs       None                  Add JavaScript Libraries like BootStrap
Print          None                  Print Page Content
Style          cStyle                 Add cStyle to page CSS content
StartHTML        None                  Add HTTP Header	to page content		
=====================	=======================================	=====================================================================

The method DecodeString is used to get HTTP request parameters.

The methods Decode and GetFileName are used for uploading files.

The methods SetCookie, Cookie & GetCookies are used for adding and reading cookies.

The methods StartHTML, ScriptsLibs, Style & Print are used for page structure and JS/CSS support.

The method URLEncode is used to encode a URL to be used in HTML pages.

Page Class

edit
=====================    ========================   =====================================================================
Method             Parameters                  Description
=====================    ========================   =====================================================================
text             x               add HTMLSpecialChars(x) to page content (accept strings and numbers)
html             cString            add html code to page content
h1              x               add x to page content between <h1> and </h1>
h2              x               add x to page content between <h2> and </h2>
h3              x               add x to page content between <h3> and </h3>
h4              x               add x to page content between <h4> and </h4>
h5              x               add x to page content between <h5> and </h5>
h6              x               add x to page content between <h6> and </h6>
p              aPara             HTML <p> </p>, uses aPara List as Hash to get attributes
NewLine           None             add <br /> to page content
AddAttributes        aPara             Convert aPara list as hash to HTML element attributes
Link             aPara             HTML <a href> and </a>, uses aPara List as Hash to get attributes
Image            aPara             HTML <img>, uses aPara List as Hash to get attributes
Button            aPara             HTML <input type="button">, uses aPara List as Hash to get attributes
ButtonLink          aPara             HTML <input type="button">, uses link attribute to navigate to link 
Textbox           aPara             HTML <input type="text">, uses aPara List as Hash to get attributes
Editbox           aPara             HTML <textarea> and </textarea>, uses aPara to get attributes
Combobox           aPara             HTML <select>, uses items attribute as list for <option>
Listbox           aPara             HTML <select multiple='multiple'>, uses items attribute for <option>
ulstart           aPara             HTML <ul>
ulend            aPara             HTML </ul>
listart           aPara             HTML <li>
liend            aPara             HTML </li>
List2UL           aList             Generate HTML <ul> including items from Ring List items
DivStart           aPara             HTML <div>, uses aPara List as Hash to get attributes
NavStart           aPara             HTML <nav>, uses aPara List as Hash to get attributes
SpanStart          aPara             HTML <span>, uses aPara List as Hash to get attributes
BoxStart           None             Generate Div with black background to be used as page header
DivEnd            None             HTML </div>
NavEnd            None             HTML </nav>
SpanEnd           None             HTML </span>
BoxEnd            None             HTML </div>, the same as divend()
FormStart          cAction            HTML <form>, with cAction as the action attribute or an empty value
FormPost           cAction            HTML <form method="post"> , with cAction as the action attribute
FormEnd           None             HTML </form>
Submit            aPara             HTML <input type="submit">
Hidden            cName,cValue         HTML <input type="hidden">
FormUpload          x               HTML Form, method="post" enctype="multipart/form-data" and x = action                
UploadFile          x               HTML <input type="file"> and name = x
Video            aPara             HTML <video>
Audio            aPara             HTML <audio>
GetColor           aPara             Select Color
Radio            aPara             HTML <input type="radio">
Checkbox           aPara             HTML <input type="checkbox">
Spinner           aPara             HTML <input type="number">
Slider            aPara             HTML <input type="range">
TableStart          aPara             HTML <table>
TableEnd           None             HTML </table>
RowStart           aPara             HTML <tr>
RowEnd            None             HTML </tr>
CellStart          aPara             HTML <td>
CellEnd           None             HTML </td>
HeaderStart         aPara             HTML <th>
HeaderEnd          None             HTML </th>
=====================    ========================   =====================================================================

aPara in the page methods is a list contains attributes and values. Using aPara we can set values for the next attributes

	classname id name align style dir value onclick oncontextmenu ondblclick
	onmousedown onmouseenter onmouseleave onmousemove onmouseover onmouseout
	onmouseup onkeydown onkeypress onkeyup onabort onbeforeunload onerror
	onhashchange onload onpageshow onpagehide onresize onscroll onunload
	onblur onchange onfocus onfocusin onfocusout oninput oninvalid onreset
	onsearch onselect onsubmit ondrag ondragend ondragenter ondragleave
	ondragover ondragstart ondrop oncopy oncut onpaste onafterprint 
	onbeforeprint oncanplay oncanplaythrough ondurationchange onemptied
	onended onloadeddata onloadedmetadata onloadstart onpause onplay
	onplaying onprogress onratechange onseeked onseeking onstalled onsuspend
	ontimeupdate onvolumechange onwaiting animationend animationiteration
	animationstart transitionend onmessage onopen onmousewheel ononline
	onoffline onpostate onshow onstorage ontoggle onwheel ontouchcancel
	ontouchend ontouchmove ontouchstart color opacity background backgroundattachment
	backgroundcolor backgroundimage backgroundposition backgroundrepeat backgroundclip
	backgroundorigin backgroundsize border borderbottom borderbottomcolor 
	borderbottomleftradius borderbottomrightradius borderbottomstyle borderbottomwidth 
	bordercolor borderimage borderimageoutset borderimagerepeat borderimageslice 
	borderimagesource borderimagewidth borderleft borderleftcolor borderleftstyle
	borderleftwidth borderradius borderright borderrightcolor borderrightstyle
	borderrightwidth borderstyle bordertop bordertopcolor bordertopleftradius
	bordertoprightradius bordertopstyle bordertopwidth borderwidth boxdecorationbreak
	boxshadow bottom clear clip display float height left margin marginbottom marginleft
	marginright margintop maxheight maxwidth minheight minwidth overflow overflowx
	overflowy padding paddingbottom paddingleft paddingright paddingtop position
	right top visibility width verticalalign zindex aligncontent alignitems alignself
	flex flexbasis flexdirection flexflow flexgrow flexshrink flexwrap justifycontent
	order hangingpunctuation hyphens letterspacing linebreak lineheight overflowwrap
	tabsize textalign textalignlast textcombineupright textindent textjustify
	texttransform whitespace wordbreak wordspacing wordwrap textdecoration 
	textdecorationcolor textdecorationline textdecorationstyle textshadow 
	textunderlineposition @fontface @fontfeaturevalues font fontfamily fontfeaturesettings
	fontkerning fontlanguageoverride fontsize fontsizeadjust fontstretch fontstyle
	fontsynthesis fontvariant fontvariantalternates fontvariantcaps fontvarianteastasian
	fontvariantligatures fontvariantnumeric fontvariantposition fontweight direction
	textorientation unicodebidi writingmode bordercollapse borderspacing captionside
	emptycells tablelayout counterincrement counterreset liststyle liststyleimage
	liststyleposition liststyletype @keyframes animation animationdelay animationdirection
	animationduration animationfillmode animationiterationcount animationname
	animationplaystate animationtimingfunction backfacevisibility perspective
	perspectiveorigin transform transformorigin transformstyle transition
	transitionproperty transitionduration transitiontimingfunction transitiondelay
	boxsizing content cursor imemode navdown navindex navleft navright navup
	outline outlinecolor outlineoffset outlinestyle outlinewidth resize textoverflow
	breakafter breakbefore breakinside columncount columnfill columngap columnrule
	columnrulecolor columnrulestyle columnrulewidth columnspan columnwidth columns
	widows orphans pagebreakafter pagebreakbefore pagebreakinside marks quotes
	filter imageorientation imagerendering imageresolution objectfit objectposition
	mask masktype mark markafter markbefore phonemes rest restafter restbefore
	voicebalance voiceduration voicepitch voicepitchrange voicerate voicestress
	voicevolume marqueedirection marqueeplaycount marqueespeed marqueestyle datatoggle
	dataride datatarget dataslideto dataslide datadismiss dataplacement datacontent
	datatrigger dataspy dataoffset dataoffsettop

ScriptFunctions Class

edit

This class contains methods for adding JavaScript code to the generated web page.

The class methods are merged to the Page class, so we can use the next methods with page objects directly.

==================    ==============================================    ============================================================
Method            Parameters                    Description
==================    ==============================================    ============================================================
Script          cCode                        Add cCode string between <script> and </script>
ScriptRedirection     cURL                         set window.location to cURL
ScriptFunc        cFuncName,cCode                   Define function cFuncName that contains cCode
ScriptFuncAlert      cFuncName,cMsg                    Define function cFuncName that uses alert() to print cMsg
ScriptFuncAjax      cFuncName,cLink,cDiv                 Define function cFuncName that load cLink in cDiv
ScriptFuncClean      cFuncName,cDiv                    Define function cFuncName that clear the cDiv
ScriptFuncSelect     cF,aL,cD,cR,cGR,cFC,nTO,cL1,cL2           Used to Edit/Delete Grid Record
ScriptScrollFixed     cDiv,nSize                      Set cDiv as Fixed Div with Size = nSize
==================    ==============================================    ============================================================

StyleFunctions Class

edit

This class contains methods for adding CSS to the generated web page.

Like ScriptFunctions Class, The StyleFunctions class methods are merged to the Page class, so we can use the next methods with page objects directly.

=====================    ====================    =====================================================
Method            Parameters         Description
=====================    ====================    =====================================================
StyleFloatLeft        None            Return float: left ; 
StyleFloatRight        None            Return float: right ; 
StyleSizeFull         None            Return width: 100% ; height: 100% ;
Stylecolor          x              Return " color: " + x + " ; "
Stylebackcolor        x              Return " background-color: " + x + " ;"
StyleTextCenter        None            Return "text-align: center ;"
StyleTextRight        None            Return "text-align: right ;"
StyleTextLeft         None            Return "text-align: left ;"
StyleSize           x,y             Return " width: " + x + " ; height: " + y + " ;"
StyleWidth          x              Return " width: " + x + " ;"
StyleHeight          x              Return " height: " + x + " ;"
StyleTop           x              Return " top: " + x + " ;"
StyleLeft           x              Return " Left: " + x + " ;"
StylePos           x,y             Return " top: " + x + " ;" + " Left: " + y + " ;"
StyleHorizontalCenter     None            Return " margin-right:auto ; margin-left:auto; "
StyleMarginTop        x              Return " margin-top: " + x + " ;"
StyleMarginRight       x              Return " margin-right: " + x + " ;"
StyleMarginLeft        x              Return " margin-left: " + x + " ;"
StyleDivCenter        nWidth,nHeight       Create Div in the center of the page
StyleAbsolute         None            Return " position:absolute ;"
StyleFixed          None            Return " position:fixed ;"
StyleZIndex          x              Return " z-index: " + x + " ;"
StyleFontSize         x              Return " font-size: " + x + " ;"
StyleGradient         x              Generate Gradient (x values from 1 to 60)
StyleTable          None            Set table properties
StyleTableRows        id             Set different color to even and odd rows in the table
StyleTableNoBorder      None            Return " border-style: none;"
=====================    ====================    =====================================================



Lessons/Code Generator for wrapping C/C++ Libraries

Code Generator for wrapping C/C++ Libraries

edit

In this chapter we will learn how to use the code generator to wrap C/C++ Libraries to use it in our Ring applications.



Using the tool

edit

The code generator program is parsec.ring that can be executed as any ring code using the ring interpreter.

for example to read a configuration file called test.cf to generate the source code file test.c run parsec.ring as in the next command

	ring parsec.ring test.cf test.c



Configuration file

edit

The configuration file (*.cf) is the input file that we pass to the code generator. This file determine the functions prototypes that we need to use from a C/C++ library.

Writing configuration files is simple according to the next rules



Using the function prototype

edit
  • To generate code that wraps a C function, we just write the C function prototype

Example:

	ALLEGRO_DISPLAY *al_create_display(int w, int h)
	void al_destroy_display(ALLEGRO_DISPLAY *display)
	int al_get_new_display_flags(void)
	void al_set_new_display_flags(int flags)
	int al_get_new_display_option(int option, int *importance)

The previous example will guide the code generator to generate five functions that wrap the al_create_display(), al_destroy_display(), al_get_new_display_flags(), al_set_new_display_flags() and al_get_new_display_option() functions.

The generated code will be as in the next example

	RING_FUNC(ring_al_create_display)
	{
		if ( RING_API_PARACOUNT != 2 ) {
			RING_API_ERROR(RING_API_MISS2PARA);
			return ;
		}
		if ( ! RING_API_ISNUMBER(1) ) {
			RING_API_ERROR(RING_API_BADPARATYPE);
			return ;
		}
		if ( ! RING_API_ISNUMBER(2) ) {
			RING_API_ERROR(RING_API_BADPARATYPE);
			return ;
		}
		RING_API_RETCPOINTER(al_create_display( (int ) RING_API_GETNUMBER(1),
					 (int ) RING_API_GETNUMBER(2)),"ALLEGRO_DISPLAY");
	}

	RING_FUNC(ring_al_destroy_display)
	{
	  if ( RING_API_PARACOUNT != 1 ) {
		RING_API_ERROR(RING_API_MISS1PARA);
		return ;
	  }
	  if ( ! RING_API_ISPOINTER(1) ) {
		RING_API_ERROR(RING_API_BADPARATYPE);
		return ;
	  }
	  al_destroy_display((ALLEGRO_DISPLAY *) RING_API_GETCPOINTER(1,"ALLEGRO_DISPLAY"));
	}


	RING_FUNC(ring_al_get_new_display_flags)
	{
		if ( RING_API_PARACOUNT != 0 ) {
			RING_API_ERROR(RING_API_BADPARACOUNT);
			return ;
		}
		RING_API_RETNUMBER(al_get_new_display_flags());
	}


	RING_FUNC(ring_al_set_new_display_flags)
	{
		if ( RING_API_PARACOUNT != 1 ) {
			RING_API_ERROR(RING_API_MISS1PARA);
			return ;
		}
		if ( ! RING_API_ISNUMBER(1) ) {
			RING_API_ERROR(RING_API_BADPARATYPE);
			return ;
		}
		al_set_new_display_flags( (int ) RING_API_GETNUMBER(1));
	}


	RING_FUNC(ring_al_get_new_display_option)
	{
		if ( RING_API_PARACOUNT != 2 ) {
			RING_API_ERROR(RING_API_MISS2PARA);
			return ;
		}
		if ( ! RING_API_ISNUMBER(1) ) {
			RING_API_ERROR(RING_API_BADPARATYPE);
			return ;
		}
		if ( ! RING_API_ISSTRING(2) ) {
			RING_API_ERROR(RING_API_BADPARATYPE);
			return ;
		}
		RING_API_RETNUMBER(al_get_new_display_option( (int ) RING_API_GETNUMBER(1),
					RING_API_GETINTPOINTER(2)));
		RING_API_ACCEPTINTVALUE(2) ;
	}

from the previous example we can see how much of time and effort is saved using the Code Generator.

Adding code to the generated code

edit
  • To generate code directly type it between and

Example :

	<code>
		/* some C code will be written here */
	</code>

We use this feature when we need to do something without the help of the code generator. for example including header files and defining constants using Macro.



Prefix for Functions Names

edit
  • To determine a prefix in all of the functions names type it between <funcstart> and </funcstart>

for example when we wrap the Allegro game programming library and we need all of the library functions to start with "al" we type the next code in the configuration file

	<funcstart>
	al
	</funcstart>



Generate function to wrap structures

edit
  • To generate functions that wrap structures (create/delete/get structure members)

just type the structures names between <struct> and </struct> also after the structure name you can type the structure members between { } separated by comma.

Example

	<struct>
	ALLEGRO_COLOR
	ALLEGRO_EVENT { type , keyboard.keycode , mouse.x , mouse.y }
	</struct>

from the previous example we will generate two function to create/delete the structure ALLEGRO_COLOR Also we will generate two functions to create/delete the structure ALLEGRO_EVENT and four functions to get the structure ALLEGRO_EVENT members (type, keyboard.keycode, mouse.x, mouse.y).



Register New Functions

edit

We can register functions by typing the function prototype between <register> and </register> We need this feature only when we don't provide the function prototype as input directly where we need to write the code of this function.

Example:

	<register>
	void al_exit(void)
	</register>

	<code>
	RING_FUNC(ring_al_exit)
	{
		if ( RING_API_PARACOUNT != 0 ) {
			RING_API_ERROR(RING_API_BADPARACOUNT);
			return ;
	}
	exit(0);
	}
	</code>

In the previous example we register the al_exit() function. This function is not part of the Allegro Library, it's just an extra function that we need to add. Then the code if this function is written inside and . This function call the exit() function from the C language library.

Writing comments in the configuration file

edit
  • To type comments just type it between <comment> and </comment>

Example:

	<comment>
	configuration files
	</comment>



Executing code during code generation

edit
  • To ask from the code generator to execute Ring code during reading the configuration file, just

write the code between <runcode> and </runcode>

Example:

	<runcode>
	aNumberTypes + "al_fixed"
	</runcode>

The previoud line of code add the string "al_fixed" to the list aNumberTypes, This list contains types that can be considered as numbers when the code generator find it in the function prototype.



Configuration file for the Allegro Library

edit

The next configuration file enable us to use the Allegro library functions. The configuration file size is less than 1000 lines. when the code generator take this file as input the generated source code file in the C language will be 12000 lines of code!

We can see this configuration file as a complete example about using the code generator Also we can use it to know the functions that can be used from RingAllegro when you use it to create 2D games!

	<code>
	#define ALLEGRO_NO_MAGIC_MAIN

	#include <allegro5/allegro.h>
	#include "allegro5/allegro_image.h"
	#include <allegro5/allegro_font.h>
	#include <allegro5/allegro_ttf.h>
	#include <allegro5/allegro_audio.h>
	#include <allegro5/allegro_acodec.h>
	#include <allegro5/allegro_opengl.h>
	#include <allegro5/allegro_direct3d.h>
	#include <allegro5/allegro_color.h>
	#include <allegro5/allegro_memfile.h>
	#include "allegro5/allegro_native_dialog.h"
	#include <allegro5/allegro_physfs.h>
	#include <allegro5/allegro_primitives.h>
	</code>

	<funcstart>
	al
	</funcstart>

	<struct>
	ALLEGRO_EVENT { type , keyboard.keycode , mouse.x , mouse.y }
	ALLEGRO_TIMEOUT
	ALLEGRO_SAMPLE_ID
	ALLEGRO_COLOR
	</struct>

	<register>
	void al_exit(void)
	</register>

	<code>
	RING_FUNC(ring_al_exit)
	{
		if ( RING_API_PARACOUNT != 0 ) {
			RING_API_ERROR(RING_API_BADPARACOUNT);
			return ;
		}
		exit(0);
	}
	</code>

	int al_init(void)

	<comment>
	configuration files
	</comment>

	<runcode>
	aNumberTypes + "al_fixed"
	</runcode>

	ALLEGRO_CONFIG *al_create_config(void)
	void al_destroy_config(ALLEGRO_CONFIG *config)
	ALLEGRO_CONFIG *al_load_config_file(const char *filename)
	ALLEGRO_CONFIG *al_load_config_file_f(ALLEGRO_FILE *file)
	bool al_save_config_file(const char *filename, const ALLEGRO_CONFIG *config)
	bool al_save_config_file_f(ALLEGRO_FILE *file, const ALLEGRO_CONFIG *config)
	void al_add_config_section(ALLEGRO_CONFIG *config, const char *name)

.. note:: we just provided part of the configuration file, for complete copy check the Ring source

	code distribution.

Threads Support

edit

Next, another part of the configutaiton file, it's important because we can learn from it how to add threads to our Ring applications by using a threads library.

The idea is using ring_vm_mutexfunctions() and ring_vm_runcodefromthread() to execute Ring code.

	<comment>
	Threads
	</comment>

	<code>
	void *al_func_thread(ALLEGRO_THREAD *thread, void *pPointer) 
	{  
		List *pList;
		VM *pVM;
		const char *cStr;
		pList = (List *) pPointer ;
		pVM = (VM *) ring_list_getpointer(pList,2);
		cStr = ring_list_getstring(pList,1);
		ring_vm_runcodefromthread(pVM,cStr);	
		ring_list_delete(pList);
		return NULL;
	}

	RING_FUNC(ring_al_create_thread)
	{
		ALLEGRO_THREAD *pThread;
		List *pList;
		if ( RING_API_PARACOUNT != 1 ) {
			RING_API_ERROR(RING_API_MISS1PARA);
			return ;
		}
		if ( ! RING_API_ISSTRING(1) ) {
			RING_API_ERROR(RING_API_BADPARATYPE);
			return ;
		}	
		pList = ring_list_new(0);
		ring_list_addstring(pList,RING_API_GETSTRING(1));
		ring_list_addpointer(pList,pPointer);
		ring_vm_mutexfunctions((VM *) pPointer,al_create_mutex,
			al_lock_mutex,al_unlock_mutex,al_destroy_mutex);
		pThread = al_create_thread(al_func_thread, pList);
		al_start_thread(pThread);
		RING_API_RETCPOINTER(pThread,"ALLEGRO_THREAD");	
	}

	RING_FUNC(ring_al_run_detached_thread)
	{
		List *pList;
		if ( RING_API_PARACOUNT != 1 ) {
			RING_API_ERROR(RING_API_MISS1PARA);
			return ;
		}
		if ( ! RING_API_ISSTRING(1) ) {
			RING_API_ERROR(RING_API_BADPARATYPE);
			return ;
		}	
		pList = ring_list_new(0);
		ring_list_addstring(pList,RING_API_GETSTRING(1));
		ring_list_addpointer(pList,pPointer);
		ring_vm_mutexfunctions((VM *) pPointer,al_create_mutex,
			al_lock_mutex,al_unlock_mutex,al_destroy_mutex);
		al_run_detached_thread(al_func_thread, pList);
	}
	</code>

	<register>
	ALLEGRO_THREAD *al_create_thread(void)
	void al_run_detached_thread(void)
	</register>

	void al_start_thread(ALLEGRO_THREAD *thread)
	void al_join_thread(ALLEGRO_THREAD *thread, void **ret_value)
	void al_set_thread_should_stop(ALLEGRO_THREAD *thread)
	bool al_get_thread_should_stop(ALLEGRO_THREAD *thread)
	void al_destroy_thread(ALLEGRO_THREAD *thread)
	ALLEGRO_MUTEX *al_create_mutex(void)
	ALLEGRO_MUTEX *al_create_mutex_recursive(void)
	void al_lock_mutex(ALLEGRO_MUTEX *mutex)
	void al_unlock_mutex(ALLEGRO_MUTEX *mutex)
	void al_destroy_mutex(ALLEGRO_MUTEX *mutex)
	ALLEGRO_COND *al_create_cond(void)
	void al_destroy_cond(ALLEGRO_COND *cond)
	void al_wait_cond(ALLEGRO_COND *cond, ALLEGRO_MUTEX *mutex)

Code Generator Rules for Wrapping C++ Classes

edit
  • We can define classes between <class> and </class>
  • Between <class> and <class> we set attributes like "name, nonew, para, parent, codename, passvmpointer and abstract"
  • we set the attributes using the style attributename:value or attributename only if no values are required
  • The "name" attribute determine the class name in C++ code and this name will be the default name in the Ring code
  • The nonew instruction means that we don't need new/delete methods
  • The parent attribute determine the parent class name
  • The codename attribute determine another class name in C++ code
  • The passvmpoint instruction means passing the Ring VM pointer to the class constructor when we create new objects, this happens when we set the codename attribute to a class the we will define and this class need the Virtual Machine pointer (for example to use it to execute Ring code from C++ code).
  • The abstract instruction means that no new method is required for this class "no objects will be created".
  • Using <nodllstartup> we can avoid #include "ring.h", We need this to write our startup code.
  • Using <libinitfunc> we can change the function name that register the library functions
  • Using <ignorecpointertype> we can ignore pointer type check
  • Using the aStringTypes list when can defined new types that treated like const char *
  • Using the aBeforeReturn list when can define code that is inserted after the variable name when we return that variable from a function
  • Using the aNewMethodName list we can define another method name to be used in Ring code when we call the C++ method. this feature is required because some C++ method may be identical to Ring Keywords like "load","next","end" and "done".

Using configuration file that wrap C++ Library

edit

To run the code generator to generate code for using C++ library in the Ring application, we can do that as we did with using C libraries but here we will generate *.cpp file instead of *.c file. Also we will determine another file to be generated (*.ring). This file will contains classes in Ring code that wraps C++ functions for using C++ classes and objects.

	ring parsec.ring qt.cf ring_qt.cpp ring_qt.ring



Configuration file for the Qt Framework

edit

The next configuration file is used to wrap many Qt classes The configuration file is around 3500 lines and generate C++ code around 56000 lines and generate also Ring code around 9000 lines.

	<nodllstartup>

	<libinitfunc> ring_qt_start

	<ignorecpointertype>

	<code>

	extern "C" {
		#include "ring.h"
	}

	#include "ring_qt.h"
	#include "gpushbutton.h"
	#include "gaction.h"
	#include "glineedit.h"
	#include "gtextedit.h"
	#include "glistwidget.h"
	#include "gtreeview.h"
	#include "gtreewidget.h"
	#include "gcombobox.h"
	#include "gtabwidget.h"
	#include "gtablewidget.h"
	#include "gprogressbar.h"
	#include "gspinbox.h"
	#include "gslider.h"
	#include "gdial.h"
	#include "gwebview.h"
	#include "gcheckbox.h"
	#include "gradiobutton.h"
	#include "gbuttongroup.h"
	#include "gvideowidget.h"
	#include "gtimer.h"
	#include "gtcpserver.h"
	#include "giodevice.h"
	#include "gabstractsocket.h"
	#include "gtcpsocket.h"
	#include "gcolordialog.h"
	#include "gallevents.h"
	#include <QApplication>
	#include <QObject>
	#include <QWidget>
	#include <QLabel>
	#include <QPixmap>
	#include <QIcon>
	#include <QSize>
	#include <QPushButton>
	#include <QMainWindow>
	#include <QVBoxLayout>
	#include <QHBoxLayout>
	#include <QLineEdit>
	#include <QTextEdit>
	#include <QListWidget>
	#include <QTreeView>
	#include <QDir>
	#include <QFileSystemModel>
	#include <QTreeWidget>
	#include <QTreeWidgetItem>
	#include <QComboBox>
	#include <QVariant>
	#include <QMenuBar>
	#include <QMenu>
	#include <QToolBar>
	#include <QMainWindow>
	#include <QStatusBar>
	#include <QDockWidget>
	#include <QTabWidget>
	#include <QTableWidget>
	#include <QTableWidgetItem>
	#include <QSizePolicy>
	#include <QFrame>
	#include <QAbstractScrollArea>
	#include <QAbstractItemView>
	#include <QProgressBar>
	#include <QSpinBox>
	#include <QSlider>
	#include <QAbstractSlider>
	#include <QDateEdit>
	#include <QDateTimeEdit>
	#include <QAbstractSpinBox>
	#include <QDial>
	#include <QWebView>
	#include <QUrl>
	#include <QCheckBox>
	#include <QRadioButton>
	#include <QButtonGroup>
	#include <QMediaPlayer>
	#include <QMediaPlaylist>
	#include <QVideoWidget>
	#include <QPrinter>
	#include <QAction>
	#include <QEvent>
	#include <QMessageBox>
	#include <QTimer>
	#include <QFileDialog>
	#include <QPainter>
	#include <QPicture>
	#include <QPen>
	#include <QColor>
	#include <QPrinter>
	#include <QFont>
	#include <QWebSettings>
	#include <QBrush>
	#include <QByteArray>
	#include <QIODevice>
	#include <QAbstractSocket>
	#include <QTcpSocket>
	#include <QTcpServer>
	#include <QNetworkProxy>
	#include <QHostAddress>
	#include <QHostInfo>
	#include <QList>
	#include <QFileInfo>
	#include <QDirModel>
	#include <QModelIndex>
	#include <QFontDialog>
	#include <QDialog>
	#include <QTextCursor>
	#include <QTextBlock>
	#include <QTextDocumentFragment>
	#include <QColorDialog>
	#include <QHeaderView>
	#include <QStringList>
	#include <QKeySequence>
	#include <QLCDNumber>
	#include <QInputDialog>
	#include <QDesktopWidget>
	#include <QRect>
	#include <QTextDocument>

	extern "C" {

		#define RING_DLL __declspec(dllexport)

		RING_DLL void ringlib_init(RingState *pRingState)
		{

			new QApplication(pRingState->argc,pRingState->argv);
			ring_qt_start(pRingState) ;
		}

	}
	</code>


	<runcode>
	aStringTypes + "QString"
	aBeforeReturn + ["QString",".toStdString().c_str()"]
	aNewMethodName + ["QWebView","load","loadpage"]
	aNewMethodName + ["QMediaPlaylist","load","loadfile"]
	aNewMethodName + ["QMediaPlaylist","next","movenext"]
	aNewMethodName + ["QPainter","end","endpaint"]
	aNewMethodName + ["QPicture","load","loadfile"]
	aNewMethodName + ["QLineEdit","end","endtext"]
	aNewMethodName + ["QDialog","done","donedialog"]
	aNewMethodName + ["QTextDocument","end","enddoc"]
	aNewMethodName + ["QTextBlock","next","nextblock"]
	</runcode>

	<class>
	name: qApp
	nonew
	</class>

	<register>
	void exec(void)
	void quit(void)
	void processEvents(void)
	</register>

	<code>

	RING_FUNC(ring_qApp_quit)
	{
		qApp->quit();
	}

	RING_FUNC(ring_qApp_exec)
	{
		qApp->exec();
	}

	RING_FUNC(ring_qApp_processEvents)
	{
		qApp->processEvents();
	}

	</code>

	<class>
	name: QObject
	para: void
	</class>

	bool blockSignals(bool block)
	QObjectList children(void)
	void dumpObjectInfo(void)
	void dumpObjectTree(void)
	bool inherits(const char *className)
	void installEventFilter(QObject *filterObj)
	bool isWidgetType(void)
	void killTimer(int id)
	void moveToThread(QThread *targetThread)
	QString objectName(void)
	QObject *parent(void)
	QVariant property(const char *name)
	void removeEventFilter(QObject *obj)
	void setObjectName(QString)
	void setParent(QObject *parent)
	bool setProperty(const char *name, QVariant)
	bool signalsBlocked(void)
	int startTimer(int interval)
	QThread *thread(void)
	void deleteLater(void)

	<class>
	name: QWidget
	para: void
	parent: QObject
	</class>

	bool acceptDrops(void)
	QString accessibleDescription(void)
	QString accessibleName(void)
	void activateWindow(void)
	void addAction(QAction *action)
	void adjustSize(void)
	bool autoFillBackground(void)
	int backgroundRole(void)
	QSize baseSize(void)
	QWidget *childAt(int x, int y)
	QRect childrenRect(void)
	QRegion childrenRegion(void)
	void clearFocus(void)
	void clearMask(void)
	QMargins contentsMargins(void)
	QRect contentsRect(void)
	int contextMenuPolicy(void)
	QCursor cursor(void)
	int effectiveWinId(void)
	void ensurePolished(void)
	int focusPolicy(void)
	QWidget *focusProxy(void)
	QWidget *focusWidget(void)
	QFont font(void)
	QFontInfo fontInfo(void)
	QFontMetrics fontMetrics(void)
	int foregroundRole(void)
	QRect frameGeometry(void)
	QSize frameSize(void)
	QRect geometry(void)
	void getContentsMargins(int *left, int *top, int *right, int *bottom)
	void grabGesture(int gesture, int flags)
	void grabKeyboard(void)
	void grabMouse(void)
	int grabShortcut(QKeySequence , int context)
	QGraphicsEffect *graphicsEffect(void)
	QGraphicsProxyWidget *graphicsProxyWidget(void)
	bool hasFocus(void)
	bool hasMouseTracking(void)
	int height(void)
	int heightForWidth(int w)
	int inputMethodHints(void)
	QVariant inputMethodQuery(int query)
	void insertAction(QAction *before, QAction *action)
	bool isActiveWindow(void)
	bool isAncestorOf(QWidget *child)
	bool isEnabled(void)
	bool isEnabledTo(QWidget *ancestor)
	bool isFullScreen(void)
	bool isHidden(void)
	bool isMaximized(void)
	bool isMinimized(void)
	bool isModal(void)
	bool isVisible(void)
	bool isVisibleTo(QWidget *ancestor)
	bool isWindow(void)
	bool isWindowModified(void)
	QLayout *layout(void)
	int layoutDirection(void)
	QLocale locale(void)
	QPoint mapFrom(QWidget *parent, QPoint)
	QPoint mapFromGlobal(QPoint)
	QPoint mapFromParent(QPoint)
	QPoint mapTo(QWidget *parent, QPoint)
	QPoint mapToGlobal(QPoint pos)
	QPoint mapToParent(QPoint pos)
	QRegion mask(void)
	int maximumHeight(void)
	QSize maximumSize(void)
	int maximumWidth(void)
	int minimumHeight(void)
	QSize minimumSize(void)
	int minimumWidth(void)
	void move(int x, int y)
	QWidget *nativeParentWidget(void)
	QWidget *nextInFocusChain(void)
	QRect normalGeometry(void)
	void overrideWindowFlags(int flags)
	QPalette palette(void)
	QWidget *parentWidget(void)
	QPoint pos(void)
	QWidget *previousInFocusChain(void)
	QRect rect(void)
	void releaseKeyboard(void)
	void releaseMouse(void)
	void releaseShortcut(int id)
	void removeAction(QAction *action)
	void render(QPaintDevice *target, QPoint,QRegion, int)
	void repaint(int x, int y, int w, int h)
	void resize(int w, int h)
	bool restoreGeometry(QByteArray)
	QByteArray saveGeometry(void)
	void scroll(int dx, int dy)
	void setAcceptDrops(bool on)
	void setAccessibleDescription(QString)
	void setAccessibleName(QString)
	void setAttribute(int attribute, bool on)
	void setAutoFillBackground(bool enabled)
	void setBackgroundRole(int role)
	void setBaseSize(int basew, int baseh)
	void setContentsMargins(int left, int top, int right, int bottom)
	void setContextMenuPolicy(int policy)
	void setCursor(QCursor)
	void setFixedHeight(int h)
	void setFixedSize(int w, int h)
	void setFixedWidth(int w)
	void setFocus(int reason)
	void setFocusPolicy(int policy)
	void setFocusProxy(QWidget *w)
	void setFont(QFont)
	void setForegroundRole(int role)
	void setGeometry(int x, int y, int w, int h)
	void setGraphicsEffect(QGraphicsEffect *effect)
	void setInputMethodHints(int hints)
	void setLayout(QLayout *layout)
	void setLayoutDirection(int direction)
	void setLocale(QLocale)
	void setMask(QBitmap)
	void setMaximumHeight(int maxh)
	void setMaximumSize(int maxw, int maxh)
	void setMaximumWidth(int maxw)
	void setMinimumHeight(int minh)
	void setMinimumSize(int minw, int minh)
	void setMinimumWidth(int minw)
	void setMouseTracking(bool enable)
	void setPalette(QPalette)
	void setParent(QWidget *parent)
	void setShortcutAutoRepeat(int id, bool enable)
	void setShortcutEnabled(int id, bool enable)
	void setSizeIncrement(int w, int h)
	void setSizePolicy(int horizontal, int vertical)
	void setStatusTip(QString)
	void setStyle(QStyle *style)
	void setToolTip(QString)
	void setUpdatesEnabled(bool enable)
	void setWhatsThis(QString)
	void setWindowFilePath(QString)
	void setWindowFlags(int type)
	void setWindowIcon(QIcon)
	void setWindowIconText(QString)
	void setWindowModality(int windowModality)
	void setWindowOpacity(double level)
	void setWindowRole(QString)
	void setWindowState(int windowState)
	QSize size(void)
	QSize sizeIncrement(void)
	QSizePolicy sizePolicy(void)
	void stackUnder(QWidget *w)
	QString statusTip(void)
	QStyle *style(void)
	QString styleSheet(void)
	bool testAttribute(int attribute)
	QString toolTip(void)
	bool underMouse(void)
	void ungrabGesture(int gesture)
	void unsetCursor(void)
	void unsetLayoutDirection(void)
	void unsetLocale(void)
	void update(int x, int y, int w, int h)
	void updateGeometry(void)
	bool updatesEnabled(void)
	QRegion visibleRegion(void)
	QString whatsThis(void)
	int width(void)
	int winId(void)
	QWidget *window(void)
	QString windowFilePath(void)
	int windowFlags(void)
	QIcon windowIcon(void)
	QString windowIconText(void)
	int windowModality(void)
	double windowOpacity(void)
	QString windowRole(void)
	int windowState(void)
	QString windowTitle(void)
	int windowType(void)
	int x(void)
	int y(void)
	bool close(void)
	void hide(void)
	void lower(void)
	void raise(void)
	void setDisabled(bool disable)
	void setEnabled(bool)
	void setHidden(bool hidden)
	void setStyleSheet(QString)
	void setWindowModified(bool)
	void setWindowTitle(QString)
	void show(void)
	void showFullScreen(void)
	void showMaximized(void)
	void showMinimized(void)
	void showNormal(void)
	QWidget *find(int id)
	QWidget *keyboardGrabber(void)
	QWidget *mouseGrabber(void)
	void setTabOrder(QWidget *first, QWidget *second)

	<class>
	name: QLabel
	para: QWidget *
	parent: QWidget
	</class>

	int alignment(void)
	QWidget *buddy(void)
	bool hasScaledContents(void)
	bool hasSelectedText(void)
	int indent(void)
	int margin(void)
	QMovie *movie(void)
	bool openExternalLinks(void)
	QPicture *picture(void)
	QPixmap *pixmap(void)
	QString selectedText(void)
	int selectionStart(void)
	void setAlignment(int)
	void setBuddy(QWidget *buddy)
	void setIndent(int)
	void setMargin(int)
	void setOpenExternalLinks(bool open)
	void setScaledContents(bool)
	void setSelection(int start, int length)
	void setTextFormat(int)
	void setTextInteractionFlags(int flags)
	void setWordWrap(bool on)
	QString text(void)
	int textFormat(void)
	int textInteractionFlags(void)
	bool wordWrap(void)
	void clear(void)
	void setMovie(QMovie *movie)
	void setNum(double num)
	void setPicture(QPicture)
	void setPixmap(QPixmap)
	void setText(QString)

	<class>
	name: QPushButton
	para: QWidget *
	parent: QWidget
	codename: GPushButton
	passvmpointer
	</class>

	void setText(const char *)
	void setClickEvent(const char *)
	void setIcon(QIcon)
	void setIconSize(QSize)

	<class>
	name: QLineEdit
	para: QWidget *
	parent: QWidget
	codename: GLineEdit
	passvmpointer
	</class>

	int alignment(void)
	void backspace(void)
	QCompleter *completer(void)
	QMenu *createStandardContextMenu(void)
	void cursorBackward(bool mark, int steps)
	void cursorForward(bool mark, int steps)
	int cursorMoveStyle(void)
	int cursorPosition(void)
	int cursorPositionAt(QPoint)
	void cursorWordBackward(bool mark)
	void cursorWordForward(bool mark)
	void del(void)
	void deselect(void)
	QString displayText(void)
	bool dragEnabled(void)
	int echoMode(void)
	void end(bool mark)
	void getTextMargins(int *left, int *top, int *right, int *bottom)
	bool hasAcceptableInput(void)
	bool hasFrame(void)
	bool hasSelectedText(void)
	void home(bool mark)
	QString inputMask(void)
	void insert(QString)
	bool isModified(void)
	bool isReadOnly(void)
	bool isRedoAvailable(void)
	bool isUndoAvailable(void)
	int maxLength(void)
	QString placeholderText(void)
	QString selectedText(void)
	int selectionStart(void)
	void setAlignment(int flag)
	void setCompleter(QCompleter *c)
	void setCursorMoveStyle(int style)
	void setCursorPosition(int)
	void setDragEnabled(bool b)
	void setEchoMode(int)
	void setFrame(bool)
	void setInputMask(QString)
	void setMaxLength(int)
	void setModified(bool)
	void setPlaceholderText(QString)
	void setReadOnly(bool)
	void setSelection(int start, int length)
	void setTextMargins(int left, int top, int right, int bottom)
	void setValidator(QValidator *v)
	QString text(void)
	QMargins textMargins(void)
	QValidator *validator(void)

	void clear(void)
	void copy(void) 
	void cut(void)
	void paste(void)
	void redo(void)
	void selectAll(void)
	void setText(QString)
	void undo(void)

	void setTextChangedEvent(const char *)
	void setcursorPositionChangedEvent(const char *)
	void seteditingFinishedEvent(const char *)
	void setreturnPressedEvent(const char *)
	void setselectionChangedEvent(const char *)
	void settextEditedEvent(const char *)

.. note:: Most of the content of the previous configuration file is removed from this documentation, for a complete version see the Ring source code distribution.



Lessons/Graphics and 2D Games programming using RingAllegro

Graphics and 2D Games programming using RingAllegro

edit

In this chapter we will learn how to use the allegro game programming library in our Ring applications.

We have the file gamelib.ring that load the DLL library that contains wrappers for the Allegro functions

	Load "allegro.rh"
	Loadlib("ring_allegro.dll")

The file gamelib.ring uses the Load instruction to execute the file allegro.rh which is a ring source code file contains constants to be used in our programs. Then using the function LoadLib() we can load the DLL library "ring_allegro.dll".

To write portable code we can change the gamelib.ring to check the platform before loading the DLL/So file.



Drawing, Animation and Input

edit

The next example uses the Allegro library for drawing, moving objects on the screen and getting input from the keyboard and the mouse.

	Load "gamelib.ring"

	al_init()
	al_init_image_addon()

	display = al_create_display(640,480)

	al_show_native_message_box(display, "Hello", "Welcome",
				"Using Allegro from the Ring programming language", 
				"", 0);

	al_clear_to_color(al_map_rgb(0,0,255))

	BOUNCER_SIZE = 40
	bouncer_x = 10
	bouncer_y = 20
	bouncer = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE)
	al_set_target_bitmap(bouncer)
	al_clear_to_color(al_map_rgb(255,0,255))

	for x = 1 to 30
		bouncer_x += x 
		bouncer_y += x
		al_set_target_bitmap(al_get_backbuffer(display))
		al_clear_to_color(al_map_rgb(0,0,0))
		al_draw_bitmap(bouncer, bouncer_x, bouncer_y, 0)
		al_draw_bitmap(bouncer, 200+bouncer_x,200+ bouncer_y, 0)
		al_flip_display()
		al_rest(0.1)
	next

	al_clear_to_color(al_map_rgb(255,255,255))
	image = al_load_bitmap("man2.jpg")
	al_draw_bitmap(image,200,200,0)
	al_flip_display()
	al_rest(2)

	event_queue = al_create_event_queue()
	al_register_event_source(event_queue, al_get_display_event_source(display))

	ev = al_new_allegro_event()
	timeout = al_new_allegro_timeout()
	al_init_timeout(timeout, 0.06)

	FPS = 60
	timer = al_create_timer(1.0 / FPS)
	al_register_event_source(event_queue, al_get_timer_event_source(timer))
	al_start_timer(timer)
	redraw = true

	SCREEN_W = 640
	SCREEN_H = 480
	BOUNCER_SIZE = 32
	bouncer_x = SCREEN_W / 2.0 - BOUNCER_SIZE / 2.0
	bouncer_y = SCREEN_H / 2.0 - BOUNCER_SIZE / 2.0
	bouncer_dx = -4.0
	bouncer_dy = 4.0

	al_install_mouse()
	al_register_event_source(event_queue, al_get_mouse_event_source())

	al_install_keyboard()
	al_register_event_source(event_queue, al_get_keyboard_event_source())

	KEY_UP = 1
	KEY_DOWN = 2
	KEY_LEFT = 3
	KEY_RIGHT = 4
	Key = [false,false,false,false]

	while true
		al_wait_for_event_until(event_queue, ev, timeout)
		switch al_get_allegro_event_type(ev)
		on ALLEGRO_EVENT_DISPLAY_CLOSE
			exit
		on ALLEGRO_EVENT_TIMER
			
			# Animation
			if bouncer_x < 0 or bouncer_x > SCREEN_W - BOUNCER_SIZE
				bouncer_dx = -bouncer_dx
			ok
	 
			if bouncer_y < 0 or bouncer_y > SCREEN_H - BOUNCER_SIZE
				bouncer_dy = -bouncer_dy
			ok
	 
			bouncer_x += bouncer_dx
			bouncer_y += bouncer_dy
			
			# Keyboard
			if key[KEY_UP] and bouncer_y >= 4.0
				bouncer_y -= 4.0
			ok 
			if key[KEY_DOWN] and bouncer_y <= SCREEN_H - BOUNCER_SIZE - 4.0
				bouncer_y += 4.0
			ok 
			if key[KEY_LEFT] and bouncer_x >= 4.0
				bouncer_x -= 4.0
			ok 
			if key[KEY_RIGHT] and bouncer_x <= SCREEN_W - BOUNCER_SIZE - 4.0
				bouncer_x += 4.0
			ok
	 
			redraw = true
			
		on ALLEGRO_EVENT_MOUSE_AXES
			bouncer_x = al_get_allegro_event_mouse_x(ev)
			bouncer_y = al_get_allegro_event_mouse_y(ev)
		on ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY
			bouncer_x = al_get_allegro_event_mouse_x(ev)
			bouncer_y = al_get_allegro_event_mouse_y(ev)
		on ALLEGRO_EVENT_MOUSE_BUTTON_UP
			exit
		on ALLEGRO_EVENT_KEY_DOWN
			switch al_get_allegro_event_keyboard_keycode(ev)
				on ALLEGRO_KEY_UP
					key[KEY_UP] = true
				on ALLEGRO_KEY_DOWN
					key[KEY_DOWN] = true
				on ALLEGRO_KEY_LEFT
					key[KEY_LEFT] = true
				on ALLEGRO_KEY_RIGHT
					key[KEY_RIGHT] = true
			off
		on ALLEGRO_EVENT_KEY_UP
			switch al_get_allegro_event_keyboard_keycode(ev)
				on ALLEGRO_KEY_UP
					key[KEY_UP] = false
				on ALLEGRO_KEY_DOWN
					key[KEY_DOWN] = false
				on ALLEGRO_KEY_LEFT
					key[KEY_LEFT] = false
				on ALLEGRO_KEY_RIGHT
					key[KEY_RIGHT] = false
				on ALLEGRO_KEY_ESCAPE
					exit
			off
		off
		if redraw and al_is_event_queue_empty(event_queue)
			redraw = false		
			al_clear_to_color(al_map_rgb(0,0,0))
			al_draw_bitmap(bouncer, bouncer_x, bouncer_y, 0)
			al_flip_display()
		ok
		callgc()
	end

	al_destroy_timer(timer)
	al_destroy_allegro_event(ev)
	al_destroy_allegro_timeout(timeout)
	al_destroy_event_queue(event_queue)
	al_destroy_bitmap(bouncer)
	al_destroy_bitmap(image)
	al_destroy_display(display)


.. note:: In the previous example we used the function callgc() which is a Ring function to force calling the Garbage collector inside the While/End loop.

Program Output:

At first the program display a messagebox

 

Then we see two rectangles are moving on the screen

 

Then we see an image displayed on the screen

 

Finally we have one rectangle, and we see it moving all of the time on the screen but we can control it using the Mouse and/or the Keyborad

 

Using TrueType Fonts

edit

In this example we will see how to use TrueType Fonts *.ttf in our Games using Allegro

	Load "gamelib.ring"

	al_init()
	al_init_font_addon()
	al_init_ttf_addon()

	display = al_create_display(800,600)

	al_clear_to_color(al_map_rgb(0,0,255))
	font = al_load_ttf_font("pirulen.ttf",14,0 )
	al_draw_text(font, al_map_rgb(255,255,255), 10, 10,ALLEGRO_ALIGN_LEFT,
		 "Welcome to the Ring programming language")
	al_flip_display()
	al_rest(2)

	al_destroy_display(display)

Screen Shot:

 

Playing Sound Files

edit

The next example play a sound file

	Load "gamelib.ring"

	al_init()
	al_install_audio()
	al_init_acodec_addon()
	al_reserve_samples(1) 

	sample = al_load_sample( "footstep.wav" )

	sampleid = al_new_allegro_sample_id()
	al_play_sample(sample, 1.0, 0.0,1.0,ALLEGRO_PLAYMODE_LOOP,sampleid)

	display = al_create_display(640,480)
	al_clear_to_color(al_map_rgb(0,0,255))
	al_flip_display()
	al_rest(10)

	al_destroy_allegro_sample_id(sampleid)
	al_destroy_sample(sample)
	al_destroy_display(display)

	al_exit()



Scaling and Rotating Images

edit

The next example display and rotate an image

	Load "gamelib.ring"

	al_init()
	al_init_image_addon()

	display = al_create_display(640,480)
	al_set_target_bitmap(al_get_backbuffer(display))
	al_clear_to_color(al_map_rgb(255,255,255))

	image = al_load_bitmap("man2.jpg")
	al_draw_rotated_bitmap(image,0,0,250,250,150,0)
	al_draw_scaled_bitmap(image,0,0,250,250,20,20,400,400,0)

	al_flip_display()
	al_rest(2)

	al_destroy_bitmap(image)
	al_destroy_display(display)

Screen Shot:

 

Display Transparent Image

edit

The next example display image with white background on another image

	Load "gamelib.ring"

	al_init()
	al_init_image_addon()

	display = al_create_display(640,480)	
	imageback = al_load_bitmap("palace.jpg")
	al_draw_bitmap(imageback,0,0,0)

	image = al_load_bitmap("man4.png")
	al_convert_mask_to_alpha(image,al_map_rgb(255,255,255))
	al_draw_bitmap(image,0,0,0)
	al_flip_display()
	al_rest(10)

	al_destroy_bitmap(image)
	al_destroy_display(display)

Screen Shot:

 

Using Threads

edit

In this example we will learn how to users threads from the Allegro library

	Load "gamelib.ring"

	o1 = new mythreads 

	Func Main
		al_init()
		for k = 1 to 5
			al_create_thread("o1.thread1()")
			al_create_thread("o1.thread2()")
			al_create_thread("o1.thread3()")
		next
		al_rest(2)

	Class Mythreads

		cAppName = "Threads Application"

		Func Thread1
			for x = 1 to 5
				see x + nl	
			next
			See 'Thread(1) : Application Name : '  + cAppName + nl

		Func Thread2
			for x = 1 to 5
				see '*****' + x + nl	
			next
			See 'Thread(2) : Application Name : '  + cAppName + nl

		Func Thread3
			for x = 1 to 5
				see '!!!!' + x + nl	
			next
			See 'Thread(3) : Application Name : '  + cAppName + nl

Output:

	1
	2
	3
	4
	5
	Thread(1) : Application Name : Threads Application
	*****1
	*****2
	*****3
	*****4
	*****5
	Thread(2) : Application Name : Threads Application
	!!!!1
	!!!!2
	!!!!3
	!!!!4
	!!!!5
	Thread(3) : Application Name : Threads Application
	1
	2
	3
	4
	5
	Thread(1) : Application Name : Threads Application
	!!!!1
	!!!!2
	!!!!3
	!!!!4
	!!!!5
	Thread(3) : Application Name : Threads Application
	*****1
	*****2
	*****3
	*****4
	*****5
	Thread(2) : Application Name : Threads Application
	*****1
	*****2
	*****3
	*****4
	*****5
	Thread(2) : Application Name : Threads Application
	!!!!1
	!!!!2
	!!!!3
	!!!!4
	!!!!5
	Thread(3) : Application Name : Threads Application
	1
	2
	3
	4
	5
	Thread(1) : Application Name : Threads Application
	*****1
	*****2
	*****3
	*****1
	*****4
	*****2
	!!!!1
	*****5
	*****3
	1
	!!!!2
	Thread(2) : Application Name : Threads Application
	1
	*****4
	!!!!1
	2
	!!!!3
	!!!!4
	*****5
	!!!!2
	3
	2
	!!!!5
	Thread(2) : Application Name : Threads Application
	!!!!3
	4
	3
	Thread(3) : Application Name : Threads Application
	!!!!4
	5
	4
	!!!!5
	Thread(1) : Application Name : Threads Application
	5
	Thread(3) : Application Name : Threads Application
	Thread(1) : Application Name : Threads Application



Lessons/Desktop and Mobile development using RingQt

Desktop and Mobile development using RingQt

edit

In this chapter we will learn how to use the Qt framework classes in our Ring applications to create Desktop and Mobile Applications.

The First GUI Application

edit

In this example we will create an application to ask the user about his/her name. When the user type the name in the textbox then click on "Say Hello" button, the textbox value will be updated by adding "Hello " to the name.

	Load "guilib.ring"

	MyApp = New qApp {

		win1 = new qWidget() {

			setwindowtitle("Hello World")
			setGeometry(100,100,370,250)

			label1 = new qLabel(win1) {
				settext("What is your name ?")
				setGeometry(10,20,350,30)
				setalignment(Qt_AlignHCenter)
			}

			btn1 = new qpushbutton(win1) {
				setGeometry(10,200,100,30)
				settext("Say Hello")
				setclickevent("pHello()")
			}

			btn1 = new qpushbutton(win1) {
				setGeometry(150,200,100,30)
				settext("Close")
				setclickevent("pClose()")
			}

			lineedit1 = new qlineedit(win1) {
				setGeometry(10,100,350,30)
			}

			show()
		}

		exec()
	}

	Func pHello  
		lineedit1.settext( "Hello " + lineedit1.text())

	Func pClose 
		MyApp.quit()

Program Output:

At first we type the name in the textbox

 

Then we click on the say hello button

 

Using Layout

edit

The next example is just an upgrade to the previous application to use the vertical layout.

	Load "guilib.ring"

	MyApp = New qApp {

		win1 = new qWidget() {

			setwindowtitle("Hello World") 
			setGeometry(100,100,400,130) 
			label1 = new qLabel(win1) {
				settext("What is your name ?") 
				setGeometry(10,20,350,30) 
				setalignment(Qt_AlignHCenter)
			}
			btn1 = new qpushbutton(win1) {
				setGeometry(10,200,100,30) 
				settext("Say Hello") 
				setclickevent("pHello()")
			}
			btn2 = new qpushbutton(win1) {
				setGeometry(150,200,100,30) 
				settext("Close") 
				setclickevent("pClose()")
			}
			lineedit1 = new qlineedit(win1) {
				setGeometry(10,100,350,30) 
			}
			layout1 = new qVBoxLayout() {
				addwidget(label1)  
				addwidget(lineedit1)  
				addwidget(btn1)  
				addwidget(btn2)		
			}
			win1.setlayout(layout1) 
			show()
		}

		exec()

	}

	Func pHello  
		lineedit1.settext( "Hello " + lineedit1.text())

	Func pClose 
		MyApp.quit()

The application during the runtime!

 

Using the QTextEdit Class

edit

In this example we will use the QTextEdit Class

	Load "guilib.ring"

	New qApp {

		win1 = new qWidget() {

			setwindowtitle("QTextEdit Class")
			setGeometry(100,100,500,500)

			new qtextedit(win1) {
				setGeometry(10,10,480,480)

			}

			show()
		}

		exec()
	}

During the runtime we can paste rich text in the qtextedit widget

 

Using the QListWidget Class

edit

In this example we will use the QListWidget Class

	Load "guilib.ring"

	New qApp {

		win1 = new qWidget() {

			setGeometry(100,100,400,400)

			list1 = new qlistwidget(win1) {
				setGeometry(150,100,200,200)
				alist = ["one","two","three","four","five"]
				for x in alist additem(x) next
				setcurrentrow(3,2)
				win1.setwindowtitle("Items Count : " + count() )
			}

			btn1 = new qpushbutton(win1) {
				setGeometry(10,200,100,30)
				settext("selected item")
				setclickevent("pWork()")
			}

			btn2 = new qpushbutton(win1) {
				setGeometry(10,240,100,30)
				settext("Delete item")
				setclickevent("pWork2()")
			}

			show()
		}

		exec()
	}

	func pWork
		btn1.settext(string(list1.currentrow()))

	func pWork2
		list1 {
			takeitem(currentrow())
		}

The application during the runtime

 

Using QTreeView and QFileSystemModel

edit

In this example we will learn how to use the QTreeView widget to represent the File System

	Load "guilib.ring"

	New qApp {

		win1 = New qWidget() {

			setwindowtitle("Using QTreeView and QFileSystemModel")
			setGeometry(100,100,500,400)

			New qtreeview(win1) {
				setGeometry(00,00,500,400)
				oDir = new QDir()			
				ofile = new QFileSystemModel()
				ofile.setrootpath(oDir.currentpath())
				setmodel(ofile)
			}

			show()
		}

		exec()
	}

The application during the runtime

 

Using QTreeWidget and QTreeWidgetItem

edit

In this example we will learn about using the QTreeWidget and QTreeWidgetItem classes

	Load "guilib.ring"

	New qApp {

		win1 = new qWidget() {

			setwindowtitle("TreeWidget")
			setGeometry(100,100,400,400)

			layout1 = new qvboxlayout(win1)

			tree1 = new qtreewidget(win1) {
				setGeometry(00,00,400,400)
				setcolumncount(1)
				myitem = new qtreewidgetitem()
				myitem.settext(0,"The First Step")
				addtoplevelitem(myitem)
				for  x = 1 to 10
					myitem2 = new qtreewidgetitem()
					myitem2.settext(0,"hello"+x)
					myitem.addchild(myitem2)
					for  y = 1 to 10
						myitem3 = new qtreewidgetitem()
						myitem3.settext(0,"hello"+x)
						myitem2.addchild(myitem3)
					next
				next
				setheaderlabel("Steps Tree")
			}

			layout1.addwidget(tree1)
			setlayout(layout1)

			show()
		}

		exec()
	}

The application during the runtime

 

Using QComboBox Class

edit

In this example we will learn about using the QComboBox class

	Load "guilib.ring"

	New qApp {

		win1 = new qWidget() {

			setwindowtitle("Using QComboBox")
			setGeometry(100,100,400,400)

			New QComboBox(win1) {
				setGeometry(150,100,200,30)
				alist = ["one","two","three","four","five"]
				for x in aList additem(x,0) next
			}			

			show()
		}

		exec()
	}

The application during the runtime

 

Creating Menubar

edit

In this example we will learn about using the QMenuBar class

	Load "guilib.ring"

	MyApp = New qApp {

		win1 = new qWidget() {

			setwindowtitle("Using QMenubar")
			setGeometry(100,100,400,400)

			menu1 = new qmenubar(win1) {		
				sub1 = addmenu("File")
				sub2 = addmenu("Edit")
				sub3 = addmenu("Help")
				sub1 { 
					oAction = new qAction(win1) {
						settext("New")
					}
					addaction(oAction)
					oAction = new qAction(win1) {
						settext("Open")
					}
					addaction(oAction)
					oAction = new qAction(win1) {
						settext("Save")
					}
					addaction(oAction)
					oAction = new qAction(win1) {
						settext("Save As")
					}
					addaction(oAction)			
					addseparator()
					oAction = new qaction(win1) {
						settext("Exit")
						setclickevent("myapp.quit()")
					}
					addaction(oAction)
				}
				sub2 { 
					oAction = new qAction(win1) {
						settext("Cut")
					}
					addaction(oAction)
					oAction = new qAction(win1) {
						settext("Copy")
					}
					addaction(oAction)
					oAction = new qAction(win1) {
						settext("Paste")
					}
					addaction(oAction)
					addseparator()
					oAction = new qAction(win1) {
						settext("Select All")
					}
					addaction(oAction)
				}				
				sub3 { 
					oAction = new qAction(win1) {
						settext("Reference")
					}
					addaction(oAction)			
					sub4 = addmenu("Sub Menu")
					sub4 { 
						oAction = new qAction(win1) {
							settext("Website")
						}
						addaction(oAction)
						oAction = new qAction(win1) {
							settext("Forum")
						}
						addaction(oAction)
						oAction = new qAction(win1) {
							settext("Blog")
						}
						addaction(oAction)
					}
					addseparator()
						oAction = new qAction(win1) {
							settext("About")
						}
						addaction(oAction)			
				}
			}
			show()
		}
		exec()
	}

The application during the runtime

 

Creating Toolbar

edit

In this example we will learn about using the QToolBar class

	Load "guilib.ring"

	New qApp {

		win1 = new qMainWindow() {

			setwindowtitle("Using QToolbar")
			setGeometry(100,100,600,400)

			abtns = [
					new qpushbutton(win1) { settext("Add") } ,
					new qpushbutton(win1) { settext("Edit") } ,
					new qpushbutton(win1) { settext("Find") } ,
					new qpushbutton(win1) { settext("Delete") } ,
					new qpushbutton(win1) { settext("Exit") 
								setclickevent("win1.close()") } 
				]

			tool1 = new qtoolbar(win1) {
				for x in abtns addwidget(x) addseparator() next
				setmovable(true)
				setGeometry(0,0,500,30)			
				setFloatable(true)
			}

			show()
		}

		exec()
	}

The application during the runtime

 

Creating StatusBar

edit

In this example we will learn about using the QStatusBar class

	Load "guilib.ring"

	New qApp {

		win1 = new qMainWindow() {

			setwindowtitle("Using QStatusbar")
			setGeometry(100,100,400,400)

			status1 = new qstatusbar(win1) {
				showmessage("Ready!",0)
			}

			setstatusbar(status1)
			show()
		}

		exec()
	}

The application during the runtime

 

Using QDockWidget

edit

In this example we will learn about using the QDockWidget class

	Load "guilib.ring"

	New qApp {
	
		win1 = new qMainWindow() {
		
			setwindowtitle("QDockWidget")
			setGeometry(100,100,400,400)

			label1 = new qlabel(win1) {
				settext("Hello")
				setGeometry(300,300,100,100)
			}
			
			label2 = new qlabel(win1) {
				settext("How are you ?")
				setGeometry(100,100,100,100)
			}
			
			dock1 = new qdockwidget(win1,0) {
				setwidget(label1)
				SetAllowedAreas(1)
			}
			
			dock2 = new qdockwidget(win1,0) {
				setwidget(label2)
				SetAllowedAreas(2)
			}

			adddockwidget(Qt_LeftDockWidgetArea,dock1,Qt_Horizontal)
			adddockwidget(Qt_LeftDockWidgetArea,dock2,Qt_Vertical)

			show()
		}
		exec()
	}

The application during the runtime

 

Using QTabWidget

edit

In this example we will learn about using the QTabWidget class

	Load "guilib.ring"

	New qApp {

		win1 = new qMainWindow() {

			setwindowtitle("Using QTabWidget")
			setGeometry(100,100,400,400)

			page1 = new qwidget() {
				new qpushbutton(page1) {
					settext("The First Page")
				}
			}

			page2 = new qwidget() {
				new qpushbutton(page2) {
					settext("The Second Page")
				}
			}

			page3 = new qwidget() {
				new qpushbutton(page3) {
					settext("The Third Page")
				}
			}

			tab1 = new qtabwidget(win1) {
				inserttab(0,page1,"Page 1")
				inserttab(1,page2,"Page 2")
				inserttab(2,page3,"Page 3")
				setGeometry(100,100,400,400)
			}		

			status1 = new qstatusbar(win1) {
				showmessage("Ready!",0)
			}

			setstatusbar(status1)
			showMaximized()
		}

		exec()
	}

The application during the runtime

 

Using QTableView

edit

In this example we will learn about using the QTableView class

	Load "guilib.ring"

	New qApp {

		win1 = new qMainWindow() {

			setGeometry(100,100,1100,370)
			setwindowtitle("Using QTableWidget")

			Table1 = new qTableWidget(win1) {	

				setrowcount(10) setcolumncount(10)
				setGeometry(0,0,800,400)
				setselectionbehavior(QAbstractItemView_SelectRows)

				for x = 1 to 10
					for y = 1 to 10
						item1 = new qtablewidgetitem("R"+X+"C"+Y)
						setitem(x-1,y-1,item1)
					next
				next		 

			}

			setcentralwidget(table1)
			show()

		}

		exec()
	}


The application during the runtime

 

Using QProgressBar

edit

In this example we will learn about using the QProgressBar class

	Load "guilib.ring"

	New qApp {
		win1 = new qMainWindow() {

			setGeometry(100,100,600,150)
			setwindowtitle("Using QProgressBar")

			for x = 10 to 100 step 10
				new qprogressbar(win1) {	
					setGeometry(100,x,350,30)
					setvalue(x)
				}
			next

			show()
		}
		exec()
	}


The application during the runtime

 

Using QSpinBox

edit

In this example we will learn about using the QSpinBox class

	Load "guilib.ring"

	New qApp {
		win1 = new qMainWindow() {
			setGeometry(100,100,450,260)
			setwindowtitle("Using QSpinBox")
				new qspinbox(win1) {	
					setGeometry(50,100,350,30)
					setvalue(50)
				}
			show()
		}
		exec()
	}

The application during the runtime

 

Using QSlider

edit

In this example we will learn about using the QSlider class

	Load "guilib.ring"

	New qApp {

		win1 = new qMainWindow() {

			setGeometry(100,100,500,400)
			setwindowtitle("Using QSlider")

			new qslider(win1) {	
				setGeometry(100,100,50,130)
				settickinterval(50)				
			}

			new qslider(win1) {	
				setGeometry(100,250,250,30)
				settickinterval(50)	
				setorientation(Qt_Horizontal)			
			}

			show()

		}

		exec()
	}

The application during the runtime

 

Using QDateEdit

edit

In this example we will learn about using the QDateEdit class

	
	Load "guilib.ring"

	New qApp {
		win1 = new qMainWindow() {
			setwindowtitle("Using QDateEdit")
			setGeometry(100,100,250,100)
			new qdateedit(win1) {	
				setGeometry(20,40,220,30)
			}
			show()
		}
		exec()
	}


The application during the runtime

 

Using QDial

edit

In this example we will learn about using the QDial class

	Load "guilib.ring"

	New qApp {
		win1 = new qMainWindow() {
			setGeometry(100,100,450,500)
			setwindowtitle("Using QDial")
			new qdial(win1) {	
				setGeometry(100,100,250,300)
			}
			show()
		}
		exec()
	}

The application during the runtime

 

Using QWebView

edit

In this example we will learn about using the QWebView class

	Load "guilib.ring"

	New qApp {
		win1 = new qMainWindow() {
			setwindowtitle("QWebView")
			myweb = new qwebview(win1) {	
				setGeometry(10,10,600,600)
				loadpage(new qurl("http://google.com"))
			}
			setcentralwidget(myweb)
			showMaximized()
		}
		exec()
	}


The application during the runtime

 

Using QCheckBox

edit

In this example we will learn about using the QCheckBox class

	Load "guilib.ring"

	New qApp {
		win1 = new qMainWindow() {
			setwindowtitle("Using QCheckBox")
			new qcheckbox(win1) {	
				setGeometry(100,100,100,30)
				settext("New Customer!")
			}
			showMaximized()
		}
		exec()
	}

The application during the runtime

 

Using QRadioButton and QButtonGroup

edit

In this example we will learn about using the QRadioButton and QButtonGroup classes

	Load "guilib.ring"

	New qApp {

		win1 = new qMainWindow() {

			setwindowtitle("Using QRadioButton")

			new qradiobutton(win1) {	
				setGeometry(100,100,100,30)
				settext("One")
			}
			new qradiobutton(win1) {	
				setGeometry(100,150,100,30)
				settext("Two")
			}
			new qradiobutton(win1) {	
				setGeometry(100,200,100,30)
				settext("Three")
			}


			group2  = new qbuttongroup(win1) {
				btn4 = new qradiobutton(win1) {	
					setGeometry(200,150,100,30)
					settext("Four")
				}
				btn5 = new qradiobutton(win1) {	
					setGeometry(200,200,100,30)
					settext("Five")
				}
				addbutton(btn4,0)
				addbutton(btn5,0)

			}

			showMaximized()

		}
		exec()
	}

The application during the runtime

 

edit

In this example we will learn about creating Hyperlink using the QLabel class

	Load "guilib.ring"

	New qApp {
		win1 = new qMainWindow() {
			setwindowtitle("QLabel - Hyperlink")
			new qlabel(win1) {	
				setGeometry(100,100,100,30)
				setopenexternallinks(true)
				settext('<a href="http://google.com">Google</a>')
			}
			showMaximized()
		}
		exec()
	}

The application during the runtime

 

QVideoWidget and QMediaPlayer

edit

In this example we will learn about using the QVideoWidget and QMediaPlayer classes to play a group of movies from different positions at the same time


	Load "guilib.ring"

	New qApp {

		win1 = new qMainWindow() {

			setwindowtitle("QVideoWidget")
			
			btn1 = new qpushbutton(win1)	{
				setGeometry(0,0,100,30)
				settext("play")
				setclickevent("player.play() player2.play() 
							   player3.play() player4.play()")
			}

			videowidget = new qvideowidget(win1) {
				setGeometry(50,50,600,300)
				setstylesheet("background-color: black")			
			}

			videowidget2 = new qvideowidget(win1) {
				setGeometry(700,50,600,300)
				setstylesheet("background-color: black")
			}


			videowidget3 = new qvideowidget(win1) {
				setGeometry(50,370,600,300)
				setstylesheet("background-color: black")
			}

			videowidget4 = new qvideowidget(win1) {
				setGeometry(700,370,600,300)
				setstylesheet("background-color: black")
			}

			player = new qmediaplayer() {
				setmedia(new qurl("1.mp4"))
				setvideooutput(videowidget)
				setposition(35*60*1000)
				
			}		

			player2 = new qmediaplayer() {
				setmedia(new qurl("2.mp4"))
				setvideooutput(videowidget2)
				setposition(23*60*1000)
			}		

			player3 = new qmediaplayer() {
				setmedia(new qurl("3.mp4"))
				setvideooutput(videowidget3)
				setposition(14.22*60*1000)
			}		

			player4 = new qmediaplayer() {
				setmedia(new qurl("4.avi"))
				setvideooutput(videowidget4)
				setposition(8*60*1000)
			}		
			
			showfullscreen()		

		}

		exec()

	}

The application during the runtime

 

Using QFrame

edit

In this example we will learn about using the QFrame class

	Load "guilib.ring"

	New qApp {
		win1 = new qMainWindow() {
			setwindowtitle("Using QFrame")
			for x = 0 to 10
				frame1 = new qframe(win1,0) {	
					setGeometry(100,20+50*x,400,30)
					setframestyle(QFrame_Raised | QFrame_WinPanel)				
				}
			next
			showMaximized()
		}
		exec()
	}

The application during the runtime

 

Display Image using QLabel

edit

In this example we will learn about displaying an image using the QLabel widget

	Load "guilib.ring"

	New qApp {
		win1 = new qMainWindow() {
			setwindowtitle("QLabel - Display image")
			new qlabel(win1) {	
				image = new qpixmap("b:/mahmoud/photo/advice.jpg")
				setpixmap(image)
				setGeometry(0,0,image.width(),image.height())
			}
			showMaximized()
		}
		exec()
	}

The application during the runtime

 

edit

In this example we will learn about creating menubar and setting the window stylesheet

	Load "guilib.ring"

	New qApp {

		win1 = new qMainWindow() {

			setwindowtitle("Menubar")

			menu1 = new qmenubar(win1) {		
				sub1 = addmenu("File")
				sub1 { 
					oAction = new qAction(win1) {
						settext("New")		
						setenabled(false)
					}
					addaction(oAction)
					oAction = new qAction(win1) {
						settext("Open")
						setcheckable(true)
						setchecked(true)
						setstatustip("open new file")					 
					}
					addaction(oAction)
					oAction = new qAction(win1) {
						settext("Save")
					}
					addaction(oAction)
					oAction = new qAction(win1) {
						settext("Save As")
					}
					addaction(oAction)
				
					addseparator()
					oAction = new qaction(win1)
					oAction.settext("Exit")
					oAction.setclickevent("myapp.quit()")
					addaction(oAction)
				}			

			}
			status1 = new qstatusbar(win1) {
				showmessage("Ready!",0)
			}
			setmenubar(menu1)
			setmousetracking(true)
			setstatusbar(status1)
			setStyleSheet("color: black; selection-color: black;
			selection-background-color:white ;
			background: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1,
 			stop: 0 #eef, stop: 1 #ccf);")
			showmaximized()
		}
		exec()
	}

The application during the runtime

 

QLineEdit Events and QMessageBox

edit

In this example we will learn about using QLineEdit Events and displaying a Messagebox

	Load "guilib.ring"

	MyApp = New qApp {

		win1 = new qWidget() {

			setwindowtitle("Welcome")
			setGeometry(100,100,400,300)


			label1 = new qLabel(win1) {
				settext("What is your name ?")
				setGeometry(10,20,350,30)
				setalignment(Qt_AlignHCenter)
			}

			btn1 = new qpushbutton(win1) {
				setGeometry(10,200,100,30)
				settext("Say Hello")
				setclickevent("pHello()")
			}

			btn1 = new qpushbutton(win1) {
				setGeometry(150,200,100,30)
				settext("Close")
				setclickevent("pClose()")
			}

			lineedit1 = new qlineedit(win1) {
				setGeometry(10,100,350,30)
				settextchangedevent("pChange()")
				setreturnpressedevent("penter()")
			}

			show()
		}

		exec()
	}

	Func pHello  
		lineedit1.settext( "Hello " + lineedit1.text())

	Func pClose 
		MyApp.quit()

	Func pChange
		win1 { setwindowtitle( lineedit1.text() ) }

	Func pEnter
		new qmessagebox(win1) {
			setwindowtitle("Thanks")
			settext("Hi " + lineedit1.text() )
			setstylesheet("background-color : white")
			show()
		}

The application during the runtime

 

 

Other Widgets Events

edit

Each Qt signal can be used in RingQt, just add Set before the signal name and add event after the signal name to get the method that can be used to determine the event code.

For example the QProgressBar class contains a signal named valueChanged() To use it just use the function setValueChangedEvent()

Example:

	Load "guilib.ring"

	New qApp {
		win1 = new qMainWindow() {

			setwindowtitle("QProgressBar valueChanged Event")

			progress1 = new qprogressbar(win1) {	
				setGeometry(100,100,350,30)
				setvalue(10)
				setvaluechangedevent("pChange()")
			}

			new qpushbutton(win1) {
				setGeometry(10,10,100,30)			
				settext("increase")
				setclickevent("pIncrease()")
			}

			showMaximized()

		}

		exec()
	}

	func pIncrease
		progress1 { setvalue(value()+1)  }

	func pchange
		win1.setwindowtitle("value : " + progress1.value() )

The application during the runtime

 

Another example for the stateChanged event of the QCheckBox class

	Load "guilib.ring"

	New qApp {
		win1 = new qMainWindow() {
			setwindowtitle("QCheckBox")
			new qcheckbox(win1) {	
				setGeometry(100,100,100,30)
				settext("New Customer!")
				setstatechangedevent("pchange()")
			}
			showMaximized()
		}
		exec()
	}

	Func pChange

		new qMessageBox(Win1) {
			setWindowTitle("Checkbox")
			settext("State Changed!")
			show()
		}

The application during the runtime

 

Using the QTimer Class

edit

In this example we will learn about using the QTimer class

	Load "guilib.ring"

	new qApp {
		win1 = new qwidget() {
			setgeometry(100,100,200,70)
			setwindowtitle("Timer")
			label1 = new qlabel(win1) {
				setgeometry(10,10,200,30)
				settext(thetime()) 
			}
			new qtimer(win1) {
				setinterval(1000)
				settimeoutevent("pTime()")
				start()
			}
			show()
		}
		exec()
	}

	func ptime
		label1.settext(thetime())

	Func thetime
		return "Time : " + Time()


The application during the runtime

 

Using the QFileDialog Class

edit

Example

	Load "guilib.ring"

	New qapp {
		win1 = new qwidget() {
			setwindowtitle("open file")
			setgeometry(100,100,400,400)
			new qpushbutton(win1) {
				setgeometry(10,10,200,30)
				settext("open file")
				setclickevent("pOpen()")
			}
			show()
		}
		exec()
	}

	Func pOpen
		new qfiledialog(win1) {
			cName = getopenfilename(win1,"open file","c:\","source files(*.ring)")
			win1.setwindowtitle(cName)
		}

The application during the runtime

 

Drawing using QPainter

edit

In this example we will learn about drawing using the QPainter class

	Load "guilib.ring"
	New qapp {
		win1 = new qwidget() {
			setwindowtitle("Drawing using QPainter")
			setgeometry(100,100,500,500)
			label1 = new qlabel(win1) {
				setgeometry(10,10,400,400)
				settext("")
			}
			new qpushbutton(win1) {
				setgeometry(200,400,100,30)
				settext("draw")
				setclickevent("draw()")
			}

			show()
		}
		exec()
	}

	Func draw
			p1 = new qpicture()
			color = new qcolor() {
				setrgb(0,0,255,255)
			}
			pen = new qpen() {
				setcolor(color)
				setwidth(10)
			}
			new qpainter() {
				begin(p1)
				setpen(pen)
				drawline(500,150,950,450)
				drawline(950,550,500,150)
				endpaint()
			}
			label1 { setpicture(p1) show() }

The application during the runtime

 

Printing using QPrinter

edit

In this example we will learn how to print to PDF file using QPrinter

	Load "guilib.ring"
	new qApp {
		win1 = new qwidget() {
			setwindowtitle("Printer")
			setgeometry(100,100,500,500)
			myweb = new qwebview(win1) {	
				setgeometry(100,100,1000,500)						
				loadpage(new qurl("http://google.com"))
			} 
			new qpushbutton(win1) {
				setGeometry(20,20,100,30)			
				settext("Print")
				setclickevent("print()")
			}
			showmaximized()
		}
		exec()
	}
	
	func print
		printer1 = new qPrinter(0) {
			setoutputformat(1)	# 1 = pdf
			setoutputfilename("test.pdf")
			painter = new qpainter() {
				begin(printer1)
				myfont = new qfont("Times",50,-1,0) 			
				setfont(myfont)
				drawtext(100,100,"test")
				printer1.newpage()
				drawtext(100,100,"test2")			
				endpaint()
			}
		}

		printer1 = new qPrinter(0) {
			setoutputformat(1)	
			setoutputfilename("test2.pdf")
			myweb.print(printer1)
			myweb.show()
		}

		system ("test.pdf")
		system ("test2.pdf")

Creating More than one Window

edit

The next example demonstrates how to create more than one window

	Load "guilib.ring"
	app1 = new qapp {
		win1 = new qwidget() {
			setwindowtitle("First")
			setgeometry(100,100,500,500)

			new qpushbutton(win1) {
				setgeometry(100,100,100,30)
				settext("close")
				setclickevent("app1.quit()")
			}

			new qpushbutton(win1) {
				setgeometry(250,100,100,30)
				settext("Second")
				setclickevent("second()")
			}

			showmaximized()
		}
		exec()
	}
	 
	func second
		win2 = new qwidget() {
			setwindowtitle("Second")
			setgeometry(100,100,500,500)
			setwindowflags(Qt_dialog)
			show()
		}

The application during the runtime

 

Playing Sound

edit

Example:

	Load "guilib.ring"
	new qapp {
		win1 = new qwidget() {
			setwindowtitle("play sound!") show()	
		}
		new qmediaplayer(win1)	{
			setmedia(new qurl("footstep.wav"))
			setvolume(50) play()	
		}
		exec()
	}

Color Dialog

edit

Example:

	Load "guilib.ring"

	oApp = new myapp { start() }

	Class MyApp

		oColor  win1

		Func start

			myapp = new qapp 

			win1 = new qMainWindow() {
				setwindowtitle("Color Dialog")
				setgeometry(100,100,400,400)
			}

			new qpushbutton(win1) {
				setgeometry(10,10,100,30)
				settext("Get Color")
				setclickevent("oApp.pColor()")
			}

			win1.show()
			myapp.exec()


		Func pColor
			myobj = new qcolordialog()
			aColor = myobj.GetColor()
			r=acolor[1] g=acolor[2] b=acolor[3]	 
			win1.setstylesheet("background-color: rgb("+r+", " + g+ "," + b + ")")

The application during the runtime

 

Using qLCDNumber Class

edit

In this example we will learn about using the qLCDNumber class

	Load "guilib.ring"

	New qApp 
	{
		win1 = new qWidget() 
		{
			setwindowtitle("LCD Number")
			setgeometry(100,100,250,120)

			new qLCDNumber(win1) 
			{
				setgeometry(10,10,100,40)
				display(100)	
				
			}

			new qLCDNumber(win1) 
			{
				setgeometry(10,60,100,40)
				display(80)	
				
			}

			show()
		}
	
		exec()
	}


The application during the runtime

 

Movable Label Example

edit
	Load "guilib.ring"

	new qApp {

		win1 = new qWidget() 
		{

			label1 = new qLabel(win1) 
			{
				setText("Welcome")
				setgeometry(10,10,200,50)
				setstylesheet("color: purple ; font-size: 30pt;")
			}

			new qTimer(win1)
			{
				setInterVal(10)
				setTimeOutEvent("pMove()")
				start()
			}

			setWindowTitle("Movable Label")
			setgeometry(100,100,600,80)
			setStyleSheet("background-color: white;")
			show()

		}

		exec()
	}

	Func pMove
		label1 
		{
			move(x()+1,y())
			if x() > 600
				move(10,y())
			ok
		}


The application during the runtime

 

QMessagebox Example

edit

In this section we will learn how to check the output of the Message box

	Load "guilib.ring"

	new qApp {
		win1 = new qWidget() 
		{
			label1 = new qpushbutton(win1) 
			{
				setText("Test")
				setgeometry(10,10,200,50)
				setstylesheet("color: purple ; font-size: 30pt;")
				setclickevent("pWork()")
			}
			setWindowTitle("Messagebox")
			setgeometry(100,100,600,80)
			setStyleSheet("background-color: white;")
			show()
		}
		exec()
	}
	 
	func pWork
		new qmessagebox(win1)
		{
			setwindowtitle("messagebox title")
			settext("messagebox text")
			setInformativeText("Do you want to save your changes?")
			setstandardbuttons(QMessageBox_Yes | QMessageBox_No | QMessageBox_Close)
			result = exec()
			win1 {
				if result = QMessageBox_Yes
					setwindowtitle("Yes")
				but result = QMessageBox_No
					setwindowtitle("No")
				but result = QMessageBox_Close
					setwindowtitle("Close")
				ok
			}
		}

The application during the runtime

 

Using QInputDialog Class

edit

In the next example we will learn about using the QInputDialog class

	Load "guilib.ring"

	New QApp {

		Win1 = New QWidget () {

			SetGeometry(100,100,400,400)
			SetWindowTitle("Input Dialog")

			New QPushButton(win1) 
			{

				SetText ("Input Dialog")
				SetGeometry(100,100,100,30)
				SetClickEvent("pWork()")
			}

			Show()
		}

		exec()
	}

	Func pWork
		oInput = New QInputDialog(win1)
		{
			setwindowtitle("What is your name?")
			setgeometry(100,100,400,50)
			setlabeltext("User Name")
			settextvalue("Mahmoud")
			lcheck = exec()
			if lCheck win1.setwindowtitle(oInput.textvalue()) ok
		}

The application during the runtime

 

KeyPress and Mouse Move Events

edit

In this example we will learn how to use the Events Filter to know about KeyPress and Mouse Move Events

	Load "guilib.ring"

	new qApp {

		win1 = new qWidget()
		{
			setWindowTitle("Test using Event Filter!")
			setGeometry(100,100,400,400)
			setmousetracking(true)
			myfilter = new qallevents(win1)
			myfilter.setKeyPressEvent("pWork()")
			myfilter.setMouseButtonPressevent("pClick()")
			myfilter.setmousemoveevent("pMove()")

			installeventfilter(myfilter)

			show()
		}

		exec()
	}

	func pWork
		win1.setwindowtitle('KeyPress! : ' + myfilter.getkeycode())

	func pClick
		new qmessagebox(win1) {
			setgeometry(100,100,400,100)
			setwindowtitle("click event!")
			settext("x : " + myfilter.getx() + 
				" y : " + myfilter.gety() + " button : " +
				 myfilter.getbutton() )
			show()
		}

	func pMove
		win1.setwindowtitle("Mouse Move , X : " + myfilter.getx() +
				    " Y : " + myfilter.gety() )

The application during the runtime

 

Moving Objects using the Mouse

edit

In the next example we will learn how to program movable objects where the user can move a label

	Load "guilib.ring"

	lPress = false
	nX = 0
	nY = 0

	new qApp {

		win1 = new qWidget()
		{

			setWindowTitle("Move this label!")
			setGeometry(100,100,400,400)
			setstylesheet("background-color:white;")

			Label1 = new qLabel(Win1){
				setGeometry(100,100,200,50)
				setText("Welcome")
				setstylesheet("font-size: 30pt")
				myfilter = new qallevents(label1)
				myfilter.setEnterevent("pEnter()")
				myfilter.setLeaveevent("pLeave()")
				myfilter.setMouseButtonPressEvent("pPress()")
				myfilter.setMouseButtonReleaseEvent("pRelease()")
				myfilter.setMouseMoveEvent("pMove()")
				installeventfilter(myfilter)
			}

			show()
		}

		exec()
	}

	Func pEnter
		Label1.setStyleSheet("background-color: purple; color:white;font-size: 30pt;")

	Func pLeave
		Label1.setStyleSheet("background-color: white; color:black;font-size: 30pt;")

	Func pPress
		lPress = True	
		nX = myfilter.getglobalx()
		ny = myfilter.getglobaly()

	Func pRelease
		lPress = False
		pEnter()

	Func pMove
		nX2 = myfilter.getglobalx()
		ny2 = myfilter.getglobaly()
		ndiffx = nX2 - nX
		ndiffy = nY2 - nY
		if lPress
			Label1 {
				move(x()+ndiffx,y()+ndiffy)
				setStyleSheet("background-color: Green;
					 color:white;font-size: 30pt;")
				nX = nX2
				ny = nY2
			}

		ok


The application during the runtime

 

 

 

Inheritance from GUI Classes

edit

Example :

	Load "guilib.ring"

	New MyWindow()

	new qApp { exec() }

	class mywindow from qwidget
		Func init
			super.init()
			setwindowtitle("First Window")
			setgeometry(100,100,400,400)
			setstylesheet("background-color: purple;")
			settooltip("my first window!")
			show()

The application during the runtime

 

Using QDesktopWidget Class

edit

In the next example we will learn about using the QDesktopWidget class

	Load "guilib.ring"

	New qApp {
		win1 = New qWidget()
		{
			resize(400,400)
			btn1 = new qPushbutton(win1)
			{
				setText("Center")
				move(100,100)
				resize(100,30)
				setClickEvent("pCenter()")
			}

			Show()
		}

		exec()
	}

	Func pCenter
		oDesktop  = new qDesktopWidget()
		oRect = oDesktop.screenGeometry( oDesktop.primaryScreen()  ) 
		win1.move((oRect.width()-win1.width()) /2 , (oRect.Height()-win1.Height())/2 )
		win1.show()

The application during the runtime

 

Simple Client and Server Example

edit

In this section we will learn about creating simple Client and Server Application

	Load "guilib.ring"

	new qApp {
		oClient = new Client { client() }
		oServer = new Server { server() }
		exec()
	}

	Class Client

		win1 lineedit1  cOutput=""
		oTcpSocket

		func client

			win1 = new qwidget() 

			new qpushbutton(win1) {
				setgeometry(50,50,100,30)
				settext("connect")
				setclickevent("oClient.Connect()")
			}

			lineedit1 = new qtextedit(win1) {
				setGeometry(150,50,200,300)
			}

			win1 {
				setwindowtitle("client")
				setgeometry(10,100,400,400)
				show()
			}

		func connect
			cOutput = "Connect to host 127.0.0.1 port 9999" + nl
			lineedit1.settext(cOutput)
			oTcpSocket = new qTcpSocket(win1) {
				setconnectedevent("oClient.pConnected()")
				setreadyreadevent("oClient.pRead()")
				connecttohost("127.0.0.1",9999,3,0)
				waitforconnected(5000)
			}			
			
		func pConnected		

			cOutput += "Connected!" + nl
			lineedit1.settext(cOutput)

		func pRead

			cOutput += "Ready Read!" + nl
			lineedit1.settext(cOutput)
			cOutput += oTcpSocket.readall().data() + nl
			lineedit1.settext(cOutput)

	Class Server

		win1 lineedit1 
		oTcpServer oTcpClient
		cOutput = ""

		func server

			win1 = new qwidget()
			
			lineedit1 = new qtextedit(win1) {
				setGeometry(150,50,200,300)
			}

			win1 {
				setwindowtitle("Server")
				setgeometry(450,100,400,400)
				show()
			}

			oTcpServer = new qTcpServer(win1) {
				setNewConnectionEvent("oServer.pNewConnection()")
				oHostAddress = new qHostAddress()
				oHostAddress.SetAddress("127.0.0.1")
				listen(oHostAddress,9999)
			}
			cOutput = "Server Started" + nl +
				   "listen to port 9999" + nl

			lineedit1.settext(cOutput)

		Func pNewConnection
		
			oTcpClient = oTcpServer.nextPendingConnection()
			cOutput += "Accept Connection" + nl
			lineedit1.settext(cOutput)
			oTcpClient {
				cStr ="Hello from server to client!"+char(13)+char(10)
				write(cStr,len(cStr))
				flush()
				waitforbyteswritten(300000)
				close()
			}

The application during the runtime

 

Notepad Application

edit

In the next example we will see simple Notepad developed using the RingQt

	Load "guilib.ring"

	cActiveFileName = ""
	aTextColor = [0,0,0]  
	aBackColor = [255,255,255]
	cFont = "MS Shell Dlg 2,14,-1,5,50,0,0,0,0,0"
	cWebsite = "http://www.google.com"

	oSearch = NULL
	oSearchValue = NULL 
	oSearchCase = NULL
	oSearchFilter = NULL
	oReplaceValue = NULL

	lAskToSave = false

	MyApp = New qApp {
		win1 = new qMainWindow() {

			setwindowtitle("Ring Notepad")
			setGeometry(100,100,400,400)
			aBtns = [
					new qpushbutton(win1) { 
						setbtnimage(self,"image/new.png") 
						setclickevent("pNew()")
						settooltip("New File")
					} ,
					new qpushbutton(win1) { 
						setbtnimage(self,"image/open.png") 
						setclickevent("pOpen()")
						settooltip("Open File")
					} ,
					new qpushbutton(win1) { 
						setbtnimage(self,"image/save.png")
						setclickevent("pSave()")
						settooltip("Save")
					 } ,
					new qpushbutton(win1) { 
						setbtnimage(self,"image/saveas.png")
						setclickevent("pSaveAs()")
						settooltip("Save As")
					 } ,
					new qpushbutton(win1) { 
						setbtnimage(self,"image/cut.png")
						setclickevent("pCut()")
						settooltip("Cut")
					 } ,
					new qpushbutton(win1) { 
						setbtnimage(self,"image/copy.png") 
						setclickevent("pCopy()")
						settooltip("Copy")
					} ,
					new qpushbutton(win1) { 
						setbtnimage(self,"image/paste.png") 
						setclickevent("pPaste()")
						settooltip("Paste")
					} ,
					new qpushbutton(win1) { 
						setbtnimage(self,"image/font.png") 
						setclickevent("pFont()")
						settooltip("Font")
					} ,
					new qpushbutton(win1) { 
						setbtnimage(self,"image/colors.jpg") 
						setclickevent("pColor()")
						settooltip("Text Color")
					} ,
					new qpushbutton(win1) { 
						setbtnimage(self,"image/search.png") 
						setclickevent("pFind()")
						settooltip("Find and Replace")
					} ,
					new qpushbutton(win1) { 
						setbtnimage(self,"image/print.png") 
						setclickevent("pPrint()")
						settooltip("Print")
					} ,
					new qpushbutton(win1) { 
						setbtnimage(self,"image/debug.png") 
						setclickevent("pDebug()")
						settooltip("Debug (Run then wait!)")
					} ,
					new qpushbutton(win1) { 
						setbtnimage(self,"image/run.png") 
						setclickevent("pRun()")
						settooltip("Run the program")
					} ,
					new qpushbutton(win1) { 
						setbtnimage(self,"image/close.png") 
						setclickevent("pQuit()")
						settooltip("Quit")
					} 
				]

			tool1 = addtoolbar("files")  {
				for x in aBtns addwidget(x) addseparator() next
			}

			menu1 = new qmenubar(win1) {		
				sub1 = addmenu("File")
				sub2 = addmenu("Edit")
				sub3 = addmenu("View")
				sub4 = addmenu("Help")
				sub1 { 
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+n"))
						setbtnimage(self,"image/new.png")
						settext("New")
						setclickevent("pNew()")
					}
					addaction(oAction)
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+o"))
						setbtnimage(self,"image/open.png") 
						settext("Open")
						setclickevent("pOpen()")
					}
					addaction(oAction)
					addseparator()
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+s"))
						setbtnimage(self,"image/save.png")
						settext("Save")
						setclickevent("pSave()")
					}
					addaction(oAction)
					addseparator()
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+e"))
						setbtnimage(self,"image/saveas.png")
						settext("Save As")
						setclickevent("pSaveAs()")
					}
					addaction(oAction)
					addseparator()
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+p"))
						setbtnimage(self,"image/print.png")
						settext("Print to PDF")
						setclickevent("pPrint()")
					}
					addaction(oAction)
					addseparator()
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+d"))
						setbtnimage(self,"image/debug.png")
						settext("Debug (Run then wait!)")
						setclickevent("pDebug()")
					}
					addaction(oAction)
					addseparator()
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+r"))
						setbtnimage(self,"image/run.png")
						settext("Run")
						setclickevent("pRun()")
					}
					addaction(oAction)
					addseparator()
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+F5"))
						setbtnimage(self,"image/run.png")
						settext("Run GUI Application (No Console)")
						setclickevent("pRunNoConsole()")
					}
					addaction(oAction)	
					addseparator()
					oAction = new qaction(win1) {
						setShortcut(new QKeySequence("Ctrl+q"))
						setbtnimage(self,"image/close.png") 
						settext("Exit")
						setstatustip("Exit")
						setclickevent("pQuit()")
					}
					addaction(oAction)
				}
				sub2 { 
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+x"))
						setbtnimage(self,"image/cut.png")
						settext("Cut")
						setclickevent("pCut()")
					}
					addaction(oAction)
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+c"))
						setbtnimage(self,"image/copy.png")
						settext("Copy")
						setclickevent("pCopy()")
					}
					addaction(oAction)
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+v"))
						setbtnimage(self,"image/paste.png")
						settext("Paste")
						setclickevent("pPaste()")
					}
					addaction(oAction)
					addseparator()
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+i"))
						setbtnimage(self,"image/font.png")
						settext("Font")
						setclickevent("pFont()")
					}
					addseparator()
					addaction(oAction)
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+t"))
						setbtnimage(self,"image/colors.jpg")
						settext("Text Color")
						setclickevent("pColor()")
					}
					addaction(oAction)
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+b"))
						setbtnimage(self,"image/colors.jpg")
						settext("Back Color")
						setclickevent("pColor2()")
					}
					addaction(oAction)
					addseparator()
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+g"))
						settext("Go to line")
						setclickevent("pGoto()")
					}
					addaction(oAction)
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+f"))
						setbtnimage(self,"image/search.png")
						settext("Find and Replace")
						setclickevent("pFind()")
					}
					addaction(oAction)
				}				
				sub3 {
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+p"))
						setbtnimage(self,"image/project.png")
						settext("Project Files")
						setclickevent("pProject()")
					}
					addaction(oAction)			
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+u"))
						setbtnimage(self,"image/source.png")
						setclickevent("pSourceCode()")
						settext("Source Code")
					}
					addaction(oAction)	
					oAction = new qAction(win1) {
						setShortcut(new QKeySequence("Ctrl+w"))
						setbtnimage(self,"image/richtext.png")
						setclickevent("pWebBrowser()")
						settext("Web Browser")
					}
					addaction(oAction)	
				}
				sub4 { 
					sub5 = addmenu("Development Tools")
					sub5 { 

						oAction = new qAction(win1) {
							settext("Programming Language")
							setclickevent("pLang()")
						}
						addaction(oAction)
						oAction = new qAction(win1) {
							settext("GUI Library")
							setclickevent("pGUI()")
						}
						addaction(oAction)
					}
					addseparator()
						oAction = new qAction(win1) {
							settext("About")
							setclickevent("pAbout()")
						}
						addaction(oAction)			
				}
			}

			setmenubar(menu1)

			status1 = new qstatusbar(win1) {
				showmessage("Ready!",0)
			}

			setstatusbar(status1)

			tree1 = new qtreeview(win1) {
				setclickedevent("pChangeFile()")
				setGeometry(00,00,200,400)
				oDir = new QDir()					
				ofile = new QFileSystemModel() {
					setrootpath(oDir.currentpath())
					myfiles = new qstringlist()
					myfiles.append("*.ring")
					myfiles.append("*.rh")
					setnamefilters(myfiles)	
					setNameFilterDisables(false)
				}
				setmodel(ofile)
				myindex = ofile.index(oDir.currentpath(),0)
				for x = 1 to ofile.columncount()
					hidecolumn(x)
				next
				setcurrentindex(myindex)
				setexpanded(myindex,true)
				header().hide()			
			}

			oDock1 = new qdockwidget(win1,0) {
				setGeometry(00,00,200,200)
				setwindowtitle("Project Files")
				setwidget(tree1)
			}

			textedit1 = new qtextedit(win1) {
				setCursorPositionChangedevent("pCursorPositionChanged()")
				setLineWrapMode(QTextEdit_NoWrap)
				setAcceptRichText(false)
				setTextChangedEvent("lAskToSave = true")
			}


			oDock2 = new qdockwidget(win1,0) {
				setwidget(textedit1)
				setwindowtitle("Source Code")
			}

			oWebBrowser = new qWidget() {	
				setWindowFlags(Qt_SubWindow)
				oWBLabel = new qLabel(win1) {
					setText("Website: ")
				}	
				oWBText = new qLineEdit(win1) {
					setText(cWebSite)
					setReturnPressedEvent("pWebGo()")
				}
				oWBGo = new qPushButton(win1) {
					setText("Go")
					setClickEvent("pWebGo()")
				}
				oWBBack = new qPushButton(win1) {
					setText("Back")
					setClickEvent("pWebBack()")
				}
				oWBLayout1 = new qHBoxLayout(win1) {
					addWidget(oWBLabel)
					addWidget(oWBText)
					addWidget(oWBGo)
					addWidget(oWBBack)
				}
				oWebView = new qWebView(win1) {
					loadpage(new qurl(cWebSite))
				}
				oWBlayout2 = new qVBoxLayout(win1) {
					addLayout(oWBLayout1)
					addWidget(oWebView)
				}
				setLayout(oWBLayout2)
			}

			oDock3 = new qdockwidget(win1,0) {
				setwidget(oWebBrowser)		
				setwindowtitle("Web Browser")
				setFeatures(QDockWidget_DocWidgetClosable)
			}	

			adddockwidget(1,oDock1,1)
			adddockwidget(2,oDock2,2)
			adddockwidget(2,oDock3,1)
		
			setwinicon(self,"image/notepad.png")

			showmaximized()
		}
		RestoreSettings()
		exec()
	}

	func pWebGo
		cWebsite = oWBText.text() 
		oWebView.LoadPage( new qurl( cWebSite ) )

	func pWebBack
		oWebView.Back()

	func pProject
		oDock1.Show()
		
	func pSourceCode
		oDock2.Show()

	func pWebBrowser
		oDock3.Show()

	func pChangeFile
		myitem = tree1.currentindex()
		if ofile.isdir(myitem)
			return
		ok
		cActiveFileName = ofile.filepath(myitem)
		textedit1.settext(read(cActiveFileName))
		textedit1.setfocus(0)
		pCursorPositionChanged()
		pSetActiveFileName()

	func pSetActiveFileName
		oDock2.setWindowTitle("Source Code : " + cActiveFileName)

	func pCursorPositionChanged
		status1.showmessage(" Line : "+(textedit1.textcursor().blocknumber()+1)+
				" Column : " +(textedit1.textcursor().columnnumber()+1) +
				" Total Lines : " + textedit1.document().linecount() ,0)

	func pGoto
		oInput = New QInputDialog(win1)
		{
			setwindowtitle("Enter the line number?")
			setgeometry(100,100,400,50)
			setlabeltext("Line")
			settextvalue("1")
			exec()
			nLine = 0 + oInput.textvalue()
			oBlock = textedit1.document().findBlockByLineNumber(nLine-1)
			oCursor = textedit1.textcursor()
			oCursor.setposition(oBlock.position(),0)
			textedit1.settextcursor(oCursor)
		}

	func pFind
		if isobject(oSearch)
			oSearch.activatewindow()
			return
		ok
		oSearch = new qWidget()
		{
			new qLabel(oSearch)
			{
				setText("Find What : ")
				setgeometry(10,10,50,30)
			}
			oSearchValue = new qlineedit(oSearch)
			{
				setgeometry(80,10,460,30)
				setReturnPressedEvent("pFindValue()")
			}
			new qLabel(oSearch)
			{
				setText("Replace with ")
				setgeometry(10,45,80,30)
			}
			oReplaceValue = new qlineedit(oSearch)
			{
				setgeometry(80,45,460,30)
			}
			oSearchCase = new qCheckbox(oSearch)
			{
				setText("Case Sensitive")
				setgeometry(80,85,100,30)
			}
			new qPushButton(oSearch)
			{
				setText("Find/Find Next")
				setgeometry(80,120,100,30)
				setclickevent("pFindValue()")
			}
			new qPushButton(oSearch)
			{
				setText("Replace")
				setgeometry(200,120,100,30)
				setclickevent("pReplace()")
			}
			new qPushButton(oSearch)
			{
				setText("Replace All")
				setgeometry(320,120,100,30)
				setclickevent("pReplaceAll()")
			}
			new qPushButton(oSearch)
			{
				setText("Close")
				setgeometry(440,120,100,30)
				setclickevent("pSearchClose()")
			}

			setwinicon(oSearch,"image/notepad.png")
			setWindowTitle("Find/Replace")		
			setStyleSheet("background-color:white;")
			setFixedsize(550,160)
			setwindowflags( Qt_CustomizeWindowHint | 
					Qt_WindowTitleHint | Qt_WindowStaysOnTopHint) 

			oSearchFilter = new qallevents(oSearch)
			oSearchFilter.setKeyPressEvent("pSearchKeyPress()")								
			installeventfilter(oSearchFilter)

			show()
		}

	Func pReplace
		oCursor = textedit1.textCursor()
		if oCursor.HasSelection() = false
			new qMessagebox(oSearch)
			{
				SetWindowTitle("Replace") 
				SetText("No Selection")
				show()	
			}
			return false
		ok
		cValue = oSearchValue.text()
		cSelected = oCursor.SelectedText()
		if oSearchCase.checkState() = Qt_Unchecked
			cValue = lower(cValue)	
			cSelected = lower(cSelected)
		ok
		if cSelected != cValue
			new qMessagebox(oSearch)
			{
				SetWindowTitle("Replace") 
				SetText("No Match")
				show()	
			}
			return false
		ok
		cValue = oReplaceValue.text()
		nStart = oCursor.SelectionStart()
		nEnd = oCursor.SelectionEnd()
		cStr = textedit1.toPlainText()
		cStr = left(cStr,nStart)+cValue+substr(cStr,nEnd+1)
		textedit1.setText(cStr)	
		return pFindValue()

	Func pReplaceAll
		cStr = textedit1.toPlainText()
		cOldValue = oSearchValue.text()
		cNewValue = oReplaceValue.text()
		if oSearchCase.checkState() = Qt_Unchecked
			# Not Case Sensitive
			cStr = SubStr(cStr,cOldValue,cNewValue,true)
		else
			# Case Sensitive
			cStr = SubStr(cStr,cOldValue,cNewValue)
		ok
		textedit1.setText(cStr)	
		new qMessagebox(oSearch)
		{
			SetWindowTitle("Replace All") 
			SetText("Operation Done")
			show()	
		}

	Func pSearchClose
		oSearch.close() 
		oSearch = NULL

	func pSearchKeyPress
		if oSearchFilter.getKeyCode() = Qt_Key_Escape
			pSearchClose()		
		ok

	func pFindValue
		oCursor = textedit1.textcursor()
		nPosStart = oCursor.Position() + 1
		cValue = oSearchValue.text()
		cStr = textedit1.toplaintext()
		cStr = substr(cStr,nPosStart)
		if oSearchCase.checkState() = Qt_Unchecked
			cStr = lower(cStr)  cValue = lower(cValue)
		ok
		nPos = substr(cStr,cValue)
		if nPos > 0
			nPos += nPosStart - 2
			oCursor = textedit1.textcursor()
			oCursor.setposition(nPos,0)
			textedit1.settextcursor(oCursor)
			oCursor = textedit1.textcursor()
			oCursor.setposition(nPos+len(cValue),1)
			textedit1.settextcursor(oCursor)
			return true
		else
			new qMessagebox(oSearch)
			{
				SetWindowTitle("Search") 
				SetText("Cannot find :" + cValue)
				show()	
			}
			return false
		ok		

	func pNofileopened
		New qMessageBox(win1) {
			setWindowTitle("Sorry")
			setText("Save the file first!")
			show()
		}

	func pDebug
		if cActiveFileName = Null return pNofileopened() ok
		cCode = "start run " + cActiveFileName + nl 
		system(cCode)

	func pRun
		if cActiveFileName = Null return pNofileopened() ok
		cCode = "start ring " + cActiveFileName + nl 
		system(cCode)

	func pRunNoConsole
		if cActiveFileName = Null return pNofileopened() ok
		cCode = "start /b ring " + cActiveFileName + nl 
		system(cCode)

	func pSave
		if cActiveFileName = NULL return pSaveAs() ok
		writefile(cActiveFileName,textedit1.toplaintext())
		status1.showmessage("File : " + cActiveFileName + " saved!",0)
		lAskToSave = false

	func pSaveAs
		new qfiledialog(win1) {
			cName = getsavefilename(win1,"Save As","","source files(*.ring)")
			if cName != NULL
				cActiveFileName = cName
				writefile(cActiveFileName,textedit1.toplaintext())
				status1.showmessage("File : " + cActiveFileName + " saved!",0)	
				pSetActiveFileName()
				lAskToSave = false
			ok	
		}

	func pPrint
		status1.showmessage("Printing to File : RingDoc.pdf",0)
		printer1 = new qPrinter(0) {
			setoutputformat(1)	# 1 = pdf
			setoutputfilename("RingDoc.pdf")
			textedit1.print(printer1)
		}
		status1.showmessage("Done!",0)
		system("RingDoc.pdf")

	func pCut
		textedit1.cut()
		status1.showmessage("Cut!",0)		

	func pCopy
		textedit1.copy()
		status1.showmessage("Copy!",0)		

	func pPaste
		textedit1.paste()
		status1.showmessage("Paste!",0)		

	func pFont
		oFontDialog = new qfontdialog(win1) {
			aFont = getfont()
		}
		textedit1.selectall()
		cFont = aFont[1]
		pSetFont()

	Func pSetFont
		myfont = new qfont("",0,0,0)
		myfont.fromstring(cFont)
		textedit1.setcurrentfont(myfont)

	Func pColor
		new qcolordialog() { aTextColor = GetColor() }	
		pSetColors()

	Func pColor2
		new qcolordialog() { aBackColor = GetColor() }	
		pSetColors()
		
	Func pSetColors
		textedit1.setstylesheet("color: rgb(" + aTextColor[1] + "," + aTextColor[2] +
					"," + aTextColor[3] + ");" + "background-color: rgb(" +
					aBackColor[1] + "," + aBackColor[2] + "," +
					aBackColor[3] + ")")

	func pOpen
		new qfiledialog(win1) {
			cName = getopenfilename(win1,"open file","c:\","source files(*.ring)")			
			if cName != NULL
				cActiveFileName = cName
				textedit1.settext(read(cActiveFileName))
			ok
		}
		
	func pNew
		new qfiledialog(win1) {
			cName = getsavefilename(win1,"New file","","source files(*.ring)")
			if cName != NULL
				write(cName,"")
				cActiveFileName = cName
				textedit1.settext(read(cActiveFileName))
				
			ok	
		}
		
	Func WriteFile cFileName,cCode
		aCode = str2list(cCode)
		fp = fopen(cFileName,"wb")
		for cLine in aCode
			fwrite(fp,cLine+char(13)+char(10))	
		next
		fclose(fp)

	Func MsgBox cTitle,cMessage
		new qMessagebox(win1) {
			setwindowtitle(cTitle)
			setText(cMessage)
			show()
		}
		

	Func pLang
		MsgBox("Programming Language",
			"This application developed using the Ring programming language")

	Func pGUI
		MsgBox("GUI Library",
			"This application uses the Qt GUI Library through RingQt")

	Func pAbout
		MsgBox("About",
			"2016, Mahmoud Fayed <msfclipper@yahoo.com>")		

	Func pSaveSettings
		cSettings = "aTextColor = ["+aTextColor[1]+","+aTextColor[2]+
				","+aTextColor[3]+"]" + nl + 
				"aBackColor = ["+aBackColor[1]+","+aBackColor[2]+
				","+aBackColor[3]+"]" + nl +
				"cFont = '" + cFont + "'" + nl + 
				"cWebSite = '" + cWebsite + "'" + nl
		cSettings = substr(cSettings,nl,char(13)+char(10))
		write("ringnotepad.ini",cSettings)
		if lAsktoSave
			new qmessagebox(win1)
			{
				setwindowtitle("Save Changes?")
				settext("Some changes are not saved!")
				setInformativeText("Do you want to save your changes?")
				setstandardbuttons(QMessageBox_Yes |
						   QMessageBox_No | QMessageBox_Cancel)
				result = exec()
				win1 {
				if result = QMessageBox_Yes
					pSave()
				but result = QMessageBox_Cancel
					return false
				ok
			}
		}	
		ok
		return true

	Func pSetWebsite
		oWebView { loadpage(new qurl(cWebSite)) }	
		oWBText  { setText(cWebSite) }		

	Func RestoreSettings
		eval(read("ringnotepad.ini"))
		pSetColors()
		pSetFont()
		pSetWebsite()

	Func pQuit
		if pSaveSettings() 
			myapp.quit()
		ok


The application during the runtime

The next screen shot demonstrates the "File" menu

 

The next window for "search and replace"

 

The next screen shot demonstrates the application main window

 

.. Note:: the functions pDebug(), pRun() and pRunNoConsole() in the previous sample are not portable! They are written in this sample for MS-Windows and we can update them for other operating systems.

The Cards Game

edit

In the next example we will see a simple Cards game developed using RingQt

Each player get 5 cards, the cards are unknown to any one. each time one player click on one card to see it. if the card is identical to another card the play get point for each card. if the card value is "5" the player get points for all visible cards.

	Load "guilib.ring"

	nScale = 1

	app1 = new qApp

	mypic = new QPixmap("cards.jpg")

	mypic2 = mypic.copy(0,(124*4)+1,79,124)
	Player1EatPic = mypic.copy(80,(124*4)+1,79,124)
	Player2EatPic= mypic.copy(160,(124*4)+1,79,124)

	aMyCards = []
	aMyValues = []
	for x1 = 0 to 3
		for y1 = 0 to 12
		  temppic = mypic.copy((79*y1)+1,(124*x1)+1,79,124)
			  aMyCards + temppic
			  aMyValues + (y1+1)
		next
	next

	nPlayer1Score = 0   nPlayer2Score=0

	do
		Page1 = new Game
		Page1.Start()
	again Page1.lnewgame

	mypic.delete()
	mypic2.delete()
	Player1EatPic.delete()
	Player2EatPic.delete()

	for t in aMyCards
		  t.delete()
	next

	func gui_setbtnpixmap pBtn,pPixmap
		pBtn {
			setIcon(new qicon(pPixmap.scaled(width(),height(),0,0)))
			setIconSize(new QSize(width(),height()))
		}

	Class Game
		
		nCardsCount = 10
		win1 layout1 label1 label2 layout2 layout3 aBtns aBtns2
		aCards nRole=1 aStatus = list(nCardsCount) aStatus2 = aStatus
		aValues        aStatusValues = aStatus  aStatusValues2 = aStatus
		Player1EatPic   Player2EatPic
		lnewgame = false
		nDelayEat = 0.5
		nDelayNewGame = 1

		func start

			win1 = new qWidget() { 
				setwindowtitle("Five") 
				setstylesheet("background-color: White")
				showfullscreen()
			}
		
			layout1 = new qvboxlayout()
		
			label1 = new qlabel(win1) {
				settext("Player (1) - Score : " + nPlayer1Score)
				setalignment(Qt_AlignHCenter | Qt_AlignVCenter)
				setstylesheet("color: White; background-color: Purple;
						 font-size:20pt")
				setfixedheight(200)
			}

			closebtn = new qpushbutton(win1)  {
				settext("Close Application")
				setstylesheet("font-size: 18px ; color : white ;
						 background-color: black ;")
				setclickevent("Page1.win1.close()")
			}
		
			aCards = aMyCards
			aValues = aMyValues

			layout2 = new qhboxlayout()

			aBtns = []

			for x = 1 to nCardsCount
				aBtns + new qpushbutton(win1) 
				aBtns[x].setfixedwidth(79*nScale)
				aBtns[x].setfixedheight(124*nScale)
				gui_setbtnpixmap(aBtns[x],mypic2)
				layout2.addwidget(aBtns[x])
				aBtns[x].setclickevent("Page1.Player1click("+x+")")
			next

			layout1.addwidget(label1)	
			layout1.addlayout(layout2)

			label2 = new qlabel(win1) {
				settext("Player (2) - Score : " + nPlayer2Score)
				setalignment(Qt_AlignHCenter | Qt_AlignVCenter)
				setstylesheet("color: white; background-color: red;
						 font-size:20pt")
				setfixedheight(200)
			}

			layout3 = new qhboxlayout()

			aBtns2 = []
			for x = 1 to nCardsCount
				aBtns2 + new qpushbutton(win1)
				aBtns2[x].setfixedwidth(79*nScale)
				aBtns2[x].setfixedheight(124*nScale)
				gui_setbtnpixmap(aBtns2[x],mypic2)
				layout3.addwidget(aBtns2[x])
				aBtns2[x].setclickevent("Page1.Player2click("+x+")")
			next

			layout1.addwidget(label2)
			layout1.addlayout(layout3)
			layout1.addwidget(closebtn)

			win1.setlayout(layout1)

			app1.exec()

		Func Player1Click x
			if nRole = 1 and aStatus[x] = 0
				nPos = ((random(100)+clock())%(len(aCards)-1)) + 1
				gui_setbtnpixmap(aBtns[x],aCards[nPos])
				del(aCards,nPos)
				nRole = 2
				aStatus[x] = 1
				aStatusValues[x] = aValues[nPos]
				del(aValues,nPos)
				Player1Eat(x,aStatusValues[x])
				checknewgame()
			ok

		Func Player2Click x
			if nRole = 2 and aStatus2[x] = 0
				nPos = ((random(100)+clock())%(len(aCards)-1)) + 1
				gui_setbtnpixmap(aBtns2[x],aCards[nPos])
				del(aCards,nPos)
				nRole = 1
				aStatus2[x] = 1
				aStatusValues2[x] = aValues[nPos]
				del(aValues,nPos)
				Player2Eat(x,aStatusValues2[x])
				checknewgame()
			ok

		Func Player1Eat nPos,nValue

			 app1.processEvents()

			 delay(nDelayEat)
			 lEat = false
			 for x = 1 to nCardsCount
				 if aStatus2[x] = 1 and (aStatusValues2[x] = nValue or nValue=5)
					aStatus2[x] = 2
					gui_setbtnpixmap(aBtns2[x],Player1EatPic)
					lEat = True
					nPlayer1Score++
				 ok
				 if (x != nPos) and (aStatus[x] = 1) and 
					(aStatusValues[x] = nValue or nValue=5)
					aStatus[x] = 2
					gui_setbtnpixmap(aBtns[x],Player1EatPic)
					lEat = True
					nPlayer1Score++
				 ok
			 next
			 if lEat
					nPlayer1Score++
					gui_setbtnpixmap(aBtns[nPos],Player1EatPic)
					aStatus[nPos] = 2
					label1.settext("Player (1) - Score : " + nPlayer1Score)
			 ok

		Func Player2Eat nPos,nValue

			 app1.processEvents()

			 delay(nDelayEat)
			 lEat = false
			 for x = 1 to  nCardsCount
				 if aStatus[x] = 1 and (aStatusValues[x] = nValue or nValue = 5)
					aStatus[x] = 2
					gui_setbtnpixmap(aBtns[x],Player2EatPic)
					lEat = True
					nPlayer2Score++
				 ok

				 if (x != nPos) and (aStatus2[x] = 1) and
					(aStatusValues2[x] = nValue or nValue=5 )
					aStatus2[x] = 2
					gui_setbtnpixmap(aBtns2[x],Player2EatPic)
					lEat = True
					nPlayer2Score++
				 ok
			 next
			 if lEat
					nPlayer2Score++
					gui_setbtnpixmap(aBtns2[nPos],Player2EatPic)
					aStatus2[nPos] = 2
					label2.settext("Player (2) - Score : " + nPlayer2Score)
			 ok

		Func checknewgame
			if isnewgame()
					  lnewgame = true

					  if nPlayer1Score > nPlayer2Score
						 label1.settext("Player (1) Wins!!!")
					  ok
					  if nPlayer2Score > nPlayer1Score
						 label2.settext("Player (2) Wins!!!")
					  ok

					  app1.processEvents()
					  delay(nDelayNewGame)

					  win1.delete()
					  app1.quit()
			ok

		Func isnewgame
			for t in aStatus
				if t = 0
					return false
				ok
			next
			for t in aStatus2
				if t = 0
					return false
				ok
			next
			return true

		Func delay x
		nTime = x * 1000
		oTest = new qTest
		oTest.qsleep(nTime)

The application during the runtime

 

.. note:: in the previous screen shot the player get the card number '5' but his score is not increased because he opened this card while no other cards are visible!

The next screen shot while running the game using a Mobile (Android)

 

.. note:: using Qt we can run the same application on other Mobile systems