Thursday, November 26, 2009

How about a new interpreter language similar to Delphi?

I'm thinking for a long time about creating a interpreted language with the hope that will improve application development by at least 200%, you might think I'm joking now or that I'm out of my mind, but read on and you will understand how development time decreases.
Did you know that you "waste" somewhere between 5 and 10% of your time writing variable types? I mean
var myvar : TMyType;
how about the time wasted "asking" Google to help you with your question? Oh... not to mention about the bad names(in most programming and interpreted languages) for functions classes, i.e. writeln, readln, print, printf, strcpy, etc.
Anywayz I don't want to waste more of your time with this kind of stuff, I'm pretty sure you got the idea until now.
Here's the grammar(until now for my "to be" interpreted language")
Language: Turbo
application|console IDENTIFIER

  include|import|use|uses 'filename.extension';// not sure yet about the include

  var IDENTIFIER[, IDENTIFIER1, IDENTIFIERN];

  class IDENTIFIER extends|for IDENTIFIER

    private|public

      var IDENTIFIER[, IDENTIFIER1, IDENTIFIERN];

      function IDENTIFIER(PARAMETER[, PARAMETER1, PARAMETER2])
      end; {function}

  end; {class}

  function IDENTIFIER(PARAMETER[, PARAMETER1, PARAMETER2])
    var IDENTIFIER[, IDENTIFIER1, IDENTIFIERN];
    | code
  end; {function}

If statement

  if CONDITION then
    |
  end; {if}

  if CONDITION then
    |
  else
    |
  end; {if]

For statement

  for var index :=|= INTEGER VALUE to|downto INTEGER VALUE [step INTEGER VALUE] do
    | in the for loop you can assign the value of "index" variable
    | as in good old Pascal
  end; {for}

While and repeat statements
  while CONDITION do
    |
  end; {while}

  repeat
    |
  until CONDITION; {repeat}

Case

  case VALUE[INTEGER, STRING, CHAR] of
    IDENTIFIER|[INTEGER|STRING|CHAR VALUE]:
      |
    end; {IDENTIFIER|[INTEGER|STRING|CHAR VALUE] case}
    else
      |
    end; {else case}
  end; {case}

Try
-- there can be 4 types of tries
1:
  try
    | just try to execute code nothing else matters
  end; {try}

2:
  try
    | execute code and execute except block on exception
  except
    |
  end; {try}

3:
  try
    | try to execute code, no matter what, the code in finally
    | block gets executed
  finally
    |
  end; {try}

4:
  try
    | try to execute code, handle exception and execute finally block
    | like two nested tries in Delphi
  except
    |
  finally
    |
  end; {try}

Initialization and finalization of a include file or application|console

  initialization
     |
  finalization
     |

end; {application|console}
As you can see there are no begins I consider as wasting time to write, any declaration ends with end keyword.
The main idea is that all function/class names tell you what it actually does, for instance StringCopy, to copy a part from a string and Console.WriteLine(I know it's like delphi combined with .NET, but it actually looks clean!).
I think it will be created in Delphi but compiled with Freepascal so it can go cross platform baby!
Anyways, I really want to read your opinions and maybe start the project with someone.

Reserved names in Access

In all projects I work, we use Postgresql as database, therefore I'm used to this kind of SQL syntax
INSERT INTO "TableName"("FieldOne", "FieldTwo", "FieldN") VALUES('Value1', 'Value2', 'ValueN');
but yesterday I had to implement and use a local database made in access and access it using ADO, all was OK until I've encountered a superficial error, I had to insert a new record but one of the fields has the name Date, now here's where the error comes, Date is a reserved word!! therefore I got a lot of errors and didn't knew where the problem came from until I've surrounded each field name between brackets like "[" and "]" in this case the field name is not treated as reserved word even though it is
-- the error
INSERT INTO aTable(FieldOne, FieldTwo, Date) VALUES('x', 'x', #2009-25-12 14:14:00#);

-- after figuring out the problem here is the new insert script
INSERT INTO aTable([FieldOne], [FieldTwo], [Date]) VALUES('x', 'x', #2009-25-12 14:14:00#);
So in order to play safe, put each field name between "[" and "]" and you will know that this won't be the error when you get sql syntax error :).
Postgre, on the other hand, has a much better syntax because, each table name or field name must be between double quotes and functions or reserved words are not.
If you know any other error like the one I've mentioned above, feel free to comment.

Friday, November 20, 2009

Delphi project explained

This is another post for Delphi beginners.
In this post I will try to explain what a Delphi project contains and how a GUI application is created.
Start Delphi > File -> New -> Application|VCL Forms Application press SHIFT+CTRL+S(this shortcut saves all files opened in Delphi IDE) save everything to a folder without naming them.
At this point you should have 4 or 5 files(I'm not sure from what version of Delphi they introduced ProjectName.dproj(xml) -- you can delete the .dproj file it will be automatically recreated) file, and here are the names of files
- Project1.dpr -- this is the program with which you should be familiar i.e.
program delphiOnSteroids;
begin
     WriteLn('Hi dudes!');
     ReadLn;
end.
- Project1.res -- this file keeps the application's icon, it can be deleted and will be recreated after IDE shows you and error file which says that the resource file cannot be found and it will be recreated
- Unit1.dfm -- files with *.dfm extension contains information about objects on the form and form information, i.e. control width, height, color, font, etc.
- Unit1.pas -- this file contains code that defines and implements a new class of form with ease.

Did you know that when you create a new form and add a few controls on the form, modify them, add events, etc. you basically create a new class without even noticing?
Here is unit1.pas after creating a new project and saving it without modifying anything but adding two variables in order to explain the private and public keywords
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm1 = class(TForm)
  private
         ImAPrivateString: String;
// ImAPrivateString can be viewed only by descendants
// of this class or by class it self
    { Private declarations }
  public
        ImAPublicInteger: Integer;
//ImAPublicInteger can be accessed publicly by
// typing the name of the identifier which is of type this class.identifier
// for instance Form1.ImAPublicInteger := 2009;
    { Public declarations }
  end;

var
  Form1: TForm1; // this is a unit variable which can be accessed from
// other units by adding this unit to it's uses clause
// i.e. uses unit1;
// this variable means nothing without this line of code in the *.dpr file
// Application.CreateForm(TForm1, Form1);
// the above procedure creates a new form of type TForm1 and assigns
// it to Form1 variable which is the name of the form in unit1

implementation

{$R *.dfm} // this is a compiler directive which tells the compiler
// something like, *whistle* hey compiler the file with same name as 
// mine but with *.dfm extension is my form's properties, you know
// what to do with them!

end.
Let's analyze the *.dpr file
program Project1; // define the name of the program
// MUST be same as filename.dpr(without ".dpr) in our case Project1.dpr

uses
  Forms, // need this in order to create forms
// as you can see here you can also declare a relative path
// for instance UnitX in '..\DistancedUnit.pas'
// you even have a comment to let you know that it's about Form1
  Unit1 in 'Unit1.pas' {Form1};

// the ProjectName.res file that I was talking about
// compiler adds this to the executable
{$R *.res}

begin
// Delphi developers are saying this:
// This used to call InitProc, which was only used for COM and CORBA.
// Neither is used with the .NET version 
// about Application.Initialize;
  Application.Initialize;
// this is something new introduced since Delphi 2007 if I'm 
// not mistaken
  Application.MainFormOnTaskbar := True;
// creates and assigns a instance of type TForm to the unit
// variable Form1 in Unit1.pas
  Application.CreateForm(TForm1, Form1);
// this will start your application and shows Form1
// if you write somewhere Application.MainForm := SomeFormVariable
// then when that form closes your application terminates!
  Application.Run;
end.
About the *.dfm files, it's actually plain text, images/resources of components are stored as hex strings, you can call a *.dfm a better storage than the *.ini file, when you call Application.CreateForm(bla bla) the application reads the *.dfm stored in the *.exe as resource and creates the controls as defined in the *.dfm with lightning speed using RTTI(Run Time Type Information).

Thursday, November 19, 2009

Delphi and C fusion

Yesterday I found out about an interesting programming language called Go.
From their website examples you can clearly see that Go is trying to shout at Delphi and C/C++ programmers, example
func main() {
  fmt.Printf("Hello, 世界\n")
}
from the above example, a Delphi programmer would say that it should be a procedure not a function(func) because it does not have a result type... a C programmer can see that void is replaced by func.

What I really hate in all programming languages is that programmers are trying to "compress" names(of function, constants, variables, etc.) so it would be less typing involved in the future, take for example strcpy, WHY the hell didn't they just name it strcopy or even StringCopy?! or strlen and so on...


Another thing I hate in C/C++/Java(and others inspired by them) is the assignment, because it's the equal sign "=" why not "==" and "=" to check equality ex. if (a=b){}, but nooo they had to use "==" which according to your math logic it means nothing, when you write IDENTIFIER = VALUE it doesn't have any logic, because you assign a value to the IDENTIFIER variable, rite?
Anywayz Go has something special which attracts me but only because it's new, I don't really think any other programming language can attract me more than Delphi, Delphi has all I really need(and if not, then hes step brother comes into play and takes over a.K.a Freepascal):
- Language is very readable
- Very powerful
- True RAD(Rapid Application Development), I really bulive that RAD comes from Delphi, can't think of any other programming language which is more RAD than Delphi...
- The most powerful IDE in the business, not to mention Delphi 7 released in 2002 which has so many freaking feauters that no other IDE at that time had...
- the list is so long but I'm tired after a long day at work so I let you think of the rest.
Don't get me wrong, I'm not one of those guys(my programming languages is better/faster/bla bla than yours), I've tried C++, C, Java, Python, Ruby and Visual Basic(I really really really hate this programming language, it has something that makes me wanna scream!) but I couldn't find other programming language that worth my time, from all mentioned above I could work in C for some time but I would give up after 2k lines of code and about 700 curly brackets(those makes you dizzzzzy).
Ok back to Go :), from what I can see Go is here and will Go pretty sooon(in my opinion), why? take this example from their website
func unhex(c byte) byte {
    switch {
    case '0' <= c && c <= '9':
        return c - '0'
    case 'a' <= c && c <= 'f':
        return c - 'a' + 10
    case 'A' <= c && c <= 'F':
        return c - 'A' + 10
    }
    return 0
}
can you see the similarity with C and Delphi? if no it's ok... take this
func unhex(c byte) byte
|    |     | |     |
|    |     | |     +-- result type as in Delphi "function unhex(c: byte): byte"
|    |     | +-- variable type similar to Delphi's "x: byte"
|    |     +-- parameter defined as in Delphi "ParamName: Type" without ":"
|    +-- function name...
+-- func -> function
from what you can see is more like: hey Mickey! take 30% Delphi, 40% C, 5% dirt and mix them up to get a 75% "programming language", but this is just me, as the authors says "Go compilers produce fast code fast. Typical builds take a fraction of a second yet the resulting programs run nearly as quickly as comparable C or C++ code."
Nearly?! wth? who cares if it's fast as C/C++, is it productive? um wait, you have to write code in Notepad :P nice... dudes! where's it's IDE?!
Will Go be more than just a joke, will it take the crown as the most used programming language? Does Go have what it takes to worth talking about, well it should... I wrote a post on it, please do visit their website, download it test it and let me know what's your opinion!

Tuesday, November 17, 2009

Delphi 2010 team easter egg

Today I was wondering what's the new team easter egg in Delphi 2010, so I went to Help > About press ALT key and type TEAM and here it is, the names of Delphi 2010 team

How to get system idle time

If you ever need to get system idle time here are two methods which will be more than helpful.
// retrieves idle time in miliseconds
function GetIdleTime: Cardinal;
const szLastInputInfo = sizeof(TLastInputInfo);
var LastInput: TLastInputInfo;
begin
     LastInput.cbSize := szLastInputInfo;
     GetLastInputInfo(LastInput);
     Result := GetTickCount -LastInput.dwTime;
end;

type TIdleTime = (itWeeks, itDays, itHours, itMin, itSec);

// retrieves idle time in hour, minutes or seconds
function GetIdleTimeEx(IdleTime: TIdleTime): Cardinal;
// because GetIdleTime returns idle time in miliseconds
// we need to transform miliseconds according to our needs
const CIT_SEC = 1000; // 1 miliseconds is 1 second
      CIT_MIN = CIT_SEC * 60; // 60 seconds is 1 minute
      CIT_HOUR = CIT_MIN * 60; // 60 minutes is 1 hour
      CIT_DAYS = CIT_HOUR * 24; // 24 hours is 1 day
      CIT_WEEKS = CIT_DAYS * 7; // 7 days is 1 week
begin
     Result := 0;
     case IdleTime of
          itWeeks: Result := GetIdleTime div CIT_WEEKS;
          itDays: Result := GetIdleTime div CIT_DAYS;
          itHours: Result := GetIdleTime div CIT_HOUR;
          itMin: Result := GetIdleTime div CIT_MIN;
          itSec: Result := GetIdleTime div CIT_SEC;
     end;//case IdleTime of
end;
Usage
ShowMessage(Format('System Idle for %d minute(s)', [GetIdleTimeEx(itMin)]));
If you need to get the idle time in seconds just use itSec in stead of itMin and so on.

Monday, November 16, 2009

Go go Multi-Threading

For those that don't know what threads are, here's your chance to understand.
A thread is like an application running in your application, each thread is a new application. If you create a new VCL Application in Delphi and hit F9 to run it boom you've created a thread.
The idea of thread is that you can accomplish multiple tasks in same time, at this time most PC's have processors with 2 or more core, this is a good thing, because a processor can handle a limited number of threads until it goes crazy and user needs to restart hes PC(it happened to me few times...).
So bottom line, why do I need threads? well think of your torrent client, could it handle 2 or more downloads in same time without threads? well it could but it would be very slow because an alternative to threads would be a list of tasks that needs to be done and a loop that will execute operation, but that would freeze your application and your brain trying to solve bugs.
Now that we know something about threads, here's how you can create your custom thread that does a custom task, first you need to create a new class which inherits from TThread defined in Classes.pas.
type TCustomThread = class(TThread)
     private
            FMin, FMax: Integer;
            Position : integer;
            ProgressBar : TProgressBar;
     private
            procedure UpdateProgress;
            procedure SetProgressBarOptions;
     public
           procedure Execute; override;
     public
           constructor Create(withProgressBar: TProgressBar);
           destructor Destroy; override;
end;
and then implement it's methods
{ TCustomThread }

constructor TCustomThread.Create(withProgressBar: TProgressBar);
begin
     FMin := 0;
     FMax := 30000;
     // assign the progress bar
     ProgressBar := withProgressBar;
     // let thread free itself
     FreeOnTerminate := True;
     // do not create suspended, let it go as soon as it is created
     inherited Create(False);
end;

destructor TCustomThread.Destroy;
begin
     ProgressBar.Position := 0;
     inherited;
end;

procedure TCustomThread.Execute;
var i : Integer;
begin
     // set progressbar options
     Synchronize(SetProgressBarOptions);
     for i := FMin to FMax do begin
         // check if Self(thread) is terminated, if so exit
         if Terminated then
            Exit;
         Position := i;
         // call Synchronize to make sure you won't get errors
         // from VCL's
         Synchronize(UpdateProgress);
     end;// for i := ProgressBar.Min to ProgressBar.Max do begin
end;

procedure TCustomThread.UpdateProgress;
begin
     // force application to repaint itself and handle messages
     Application.ProcessMessages;
     // update progress bar position
     ProgressBar.Position := Position;
end;

procedure TCustomThread.SetProgressBarOptions;
begin
     ProgressBar.Min := FMin;
     ProgressBar.Max := FMax;
end;
Let's understand what TCustomThread does, it gets created using a progressbar as parameter, I've overwritten it's Execute procedure(this is the procedure which gets executed), it executes a for loop which calls UpdateProgress with Synchronize procedure which won't raise an exception if the VCL is not thread safe.
A demo application can be downloaded from this link(only source code).

Saturday, November 14, 2009

Save/Load controls from IniFile using RTTI

Here's a nice trick that you can use if you're in a hurry and need to implement a method to save/load controls to/from a ini file.
This method is using RTTI(Run Time Type Information), actually 3 methods from TypInfo unit: IsPublishedProp(checks if object has property), GetPropValue(retrieves the value of a property) and SetPropValue(sets the value of a property).
I've created a unit which handles saving and loading.
uDGCtrlUtils.pas
unit uDGCtrlUtils;

interface

uses
    SysUtils,
    Controls,
    Classes,
    Forms,
    IniFiles;

// this is the array of properties, the names are case sensitive
const CONTROL_PROPS: array[0..4] of string =
      ('Left', 'Top', 'Width', 'Height', 'Visible');

(*
you can also add more properties like Caption
increase the length of array by 1 from 4 to 5

const CONTROL_PROPS: array[0..5] of string =
      ('Left', 'Top', 'Width', 'Height', 'Visible', 'Caption');
and add Caption in the array
*)


  procedure SaveControls(toIniFile: TIniFile; fromForm: TForm);
  procedure LoadControls(fromIniFIle: TIniFile; toForm: TForm);
  procedure SaveControlsToFile(const FileName: string; fromForm: TForm);
  procedure LoadControlsFromFile(const FileName: string; toForm: TForm);

implementation

uses TypInfo;

procedure SaveControls(toIniFile: TIniFile; fromForm: TForm);
var i, j : integer;
    obj : TComponent;
    s, sec : string;
begin
     // store the section
     sec := fromForm.Name;
     // for each component on form
     for i := 0 to fromForm.ComponentCount -1 do begin
         // get it's reference into obj
         obj := fromForm.Components[i];
         // for each property defined in array
         for j := Low(CONTROL_PROPS) to High(CONTROL_PROPS) do
             // check if component has that property using RTTI
             if IsPublishedProp(obj, CONTROL_PROPS[j]) then begin
                // format the string ComponentName.Property
                s := Format('%s.%s', [obj.Name, CONTROL_PROPS[j]]);
                // write data to ini file
                toIniFile.WriteString(sec, s, GetPropValue(obj, CONTROL_PROPS[j]));
             end;// if IsPublishedProp(obj, CONTROL_PROPS[j]) then begin
     end;// for i := 0 to fromForm.ComponentCount -1 do begin
end;

procedure LoadControls(fromIniFIle: TIniFile; toForm: TForm);
var i, j : integer;
    obj : TComponent;
    s, sec, value : string;
begin
     // store the section
     sec := toForm.Name;
     // for each component on form
     for i := 0 to toForm.ComponentCount -1 do begin
         // get it's reference into obj
         obj := toForm.Components[i];
         // for each property defined in array
         for j := Low(CONTROL_PROPS) to High(CONTROL_PROPS) do
             // check if component has that property using RTTI
             if IsPublishedProp(obj, CONTROL_PROPS[j]) then begin
                // format the string ComponentName.Property
                s := Format('%s.%s', [obj.Name, CONTROL_PROPS[j]]);
                // read data from ini file
                value := fromIniFIle.ReadString(sec, s, EmptyStr);
                // check if value is not '' (EmptyStr)
                if value <> EmptyStr then
                   // set the property
                   SetPropValue(obj, CONTROL_PROPS[j], value);
             end;// if IsPublishedProp(obj, CONTROL_PROPS[j]) then begin
     end;// for i := 0 to fromForm.ComponentCount -1 do begin
end;

procedure SaveControlsToFile(const FileName: string; fromForm: TForm);
var ini : TIniFile;
begin
     ini := TIniFile.Create(FileName);
     SaveControls(ini, fromForm);
     FreeAndNil(ini);
end;

procedure LoadControlsFromFile(const FileName: string; toForm: TForm);
var ini : TIniFile;
begin
     ini := TIniFile.Create(FileName);
     LoadControls(ini, toForm);
     FreeAndNil(ini);
end;

end.
Example of usage
// saving
...
begin
     if SaveDialog.Execute then
        SaveControlsToFile(SaveDialog.FileName, Self);
end;

// loading
...
begin
     if OpenDialog.Execute then
        LoadControlsFromFile(OpenDialog.FileName, Self);
end;
You can do anything you wish with the above unit, modify, sell, use in commercial products, etc.

Tuesday, November 10, 2009

Logical error

Yesterday a friend of mine asked me something this:

Facts:
- you have 3 units, u1, u2 and u3.
- u1 is the main unit which contains main form with a button called Button1.
- u2 contains a global function called Sum declared as
function Sum(a, b: integer): integer:
begin
     Result := a + b;
end;
- u3 also contains a global function called Sum declared as
function Sum(a, b: integer): integer:
begin
     Result := a * b;
end;
- u1(the main unit) has u2 and u3 in uses clause and on Button1's OnClick event has the fallowing code
...
begin
     ShowMessage('Result = ' + IntToStr(Sum(3, 3)));
end;

Question: What would be the result of using Sum function with 3 as first parameter and 3 as second parameter?
I know you tend to say 6 as result but Delphi says NO! This is a so called logical error because if you have two units which both have a function called Sum(in this case) Delphi will use Sum function from last unit added in uses clause.
You don't bulive me? then test it yourself, here's the code

unit1.pas
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses unit2, unit3;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
     ShowMessage('Result = ' + IntToStr(Sum(3, 3)));
end;

end.

unit2.pas
unit Unit2;

interface

function sum(a, b: integer): integer;

implementation

function sum(a, b: integer): integer;
begin
     Result := a + b;
end;

end.

unit3.pas
unit Unit3;

interface

function sum(a, b: integer): integer;

implementation

function sum(a, b: integer): integer;
begin
     Result := a * b;
end;

end.

Sunday, November 8, 2009

Another interpreter with source code

There are a lot of Delphi interpreters out there, if you know some that worth mentioning and I didn't post them please comment on this post or e-mail me.
TArtFormula is a nice interpreter both mathematical and automation, I'm not so good at writing or advertising so I just copy-paste the info from Artem Parlyuk's(author) web site http://artsoft.nm.ru/works.html

ArtFormula package contains two nonvisual Delphi componenst for symbolic expression parsing and evaluation. Provides runtime scripting engine for automating your programs.

Provides:
7 arithmetic operations
10 logical operations
6 bitwise operations
string concatenation
22 arithmetic functions
10 statistical functions
2 logical functions
16 string functions
13 date functions
14 programming functions
User defined constant
Up to 255 user defined variables
Up to 255 user defined functions (modules)
Symbolical differentiation of functions with basic simplification of resulting derivatives

Arithmetic operation:
x + y, x - y, x * y, x / y, x % y (Mod), x ^ y (power), x\ y (Div)

Logical operation (true=1, false=0):
x > y, x < y, x >= y, x <= y, x = y, x <> y, ! x (not), x & y (and), x | y (or), x xor y

Bitwise operations:
x && y (band), x || y (bor), !!x (bnot), x bxor y, x >> y (shr), x << y (shl) Predefined constants:
Pi = 3.1415926535897932385
True = 1
False = 0

Functions:
sin, cos, tan, sinh, cosh, tanh, asin, acos, atan, asinh, acosh, atanh, sqrt, exp, log, lg (log base 10), int (integer part of a number), frac (fractional part of a number), abs, sign, rnd, randomize
max(x,y...), min(x,y,...), count(x,y,...), sum(x,y,...), sumofsquares(x,y,...), avg(x,y,...), variance(x,y,...), variancep(x,y,...), stddev(x,y,...), stddevp(x,y,...)
iff(cond,x,y) (if cond = true then result = x else result = y),
isnumber(x)
chr(x), length(s), trim(s), trimleft(s), trimright(s) lowercase(s), uppercase(s), midstr(s,x,y), leftstr(s,x), rightstr(s,x), pos(s,t), code(s), format(s,x), formatf(s,x), stringofchar(c,n), concat(s1,s2,...)
date(s), now, formatdate(s,d), year(d), month(d), day(d), hour(d), minute(d), second(d), millisecond(d), isleapyear(n), dayofweek(d), encodedate(y,m,d)

Programming:

TArtFormula provides two styles of programming: formula style and scripting style. The first style assumes that all statements have the form of function call. The second style imply that you use common program language notation.

For example:

block(defines('i','n'), set('n',1),
series(set('i',1), val('i')<=5, inc('i'), set('n',val('n')*val('i'))), msg('5! = '+val('n'),'result',0)) Is equal to: begin var 'i', 'n' end; $n:=1; for $i:=1; $i<=5; $i++ do $n := $n*$i; next; msg('5! = '+val('n'),'result',0); end You can mix two styles in one program. TArtFormula programming language supports: Variables definitions Assigmnent statement Increment and Decrement operations Return function Compound statement (BEGIN... END) IF statement WHILE loop UNTIL loop FOR loop Interface functions: msg('text','caption',props), input('caption', 'text', defvalue) Spreadsheet applicatiuon:

TArtFormula can be used in spreadsheet application. E.g. using GetVarsCount and GetVarValue event handlers one can implement calculation of sum(a1:b4), avg(c1:c99) and similar function calls, where a1:b4 and c1:c99 are range of sheet cells.

Retrieve special folders using static class

There are many times when you need the path to System32 or Windows folder or event the drive where windows is installed, at this time you need to get those paths dynamically because not everyone installs windows on default drive C:.
I've created a class specially for that reason without using the shell functions
unit uDGSysFolders;

interface

uses
    SysUtils,
    Windows;

(* define a TBuffer type as array of char *)
type TBuffer = array[0..250] of Char;

(* store it's size in a constant for faster access *)
const szBuffer = sizeof(TBuffer);

(* declare a static(doesn't need creation) class *)
type DGSystemFolders = class
     public
           (* C:\Windows\System32 *)
           class function System32Folder: string;
           (* C:\Windows *)
           class function WindowsFolder: string;
           (* C:\ *)
           class function WindowsDrive: string;
           (* C *)
           class function WindowsDriveChar: Char;
     end;

implementation

{ DGSystemFolders }

class function DGSystemFolders.System32Folder: string;
var Buffer : TBuffer;
begin
     GetSystemDirectory(Buffer, szBuffer);
     Result := Buffer;
end;

class function DGSystemFolders.WindowsDrive: string;
var tmp : string;
begin
     tmp := System32Folder;
     Result := Copy(tmp, 1, Pos('\', tmp));
end;

class function DGSystemFolders.WindowsDriveChar: Char;
var tmp : string;
begin
     tmp := System32Folder;
     Result := tmp[1];
end;

class function DGSystemFolders.WindowsFolder: string;
var tmp : string;
    i : integer;
begin
     tmp := System32Folder;
     for i := Length(tmp) downto 1 do
         if tmp[i] = '\' then begin
            Result := Copy(tmp, 1, i -1);
            Exit;
         end;// if tmp[i] = '\' then begin
end;

end.
Usage: add uDGSysFolders to uses clause
...
begin
     ShowMessage(DGSystemFolders.System32Folder);
end;

Saturday, November 7, 2009

Make sure an event is not fired

Recently I've been assigned with a task, this task is about making sure that an event will not fire unless user has the right to fire it.
In other words, you have a button in a multi user application and user X does not have the right to delete from database or to add to database, this can be easily done by writing Button.Enabled := False right? wrong, what if the user has some knowledge about windows, I mean he knows how to enable/disable a control with external applications like WinSpy++ or any other software which has option to modify a windows control behavior.
In this case you need a slick way to be absolutely sure that is not possible(it's not 100% sure only 99.99% because softice can come into play but there are few people capable to work with it and at that time you can't really do anything to protect your application) here's my implementation:
I've started by creating a unit which defines and implements two classes: TCtrlHolder and TCtrlHolderList.
type TCtrlHolder = class
                 public
                       Obj : TButton;
                       Name : string;
                       AllowedClick,
                       DeniedClick : TNotifyEvent;
                 public
                       procedure SetEnable(T: boolean);
                 public
                       constructor Create(onButton: TButton);
     end;// type TCtrlHolder = class

type TCtrlHolderList = class
                     private
                            FCtrlList : TList;
                            procedure DisplayDeniedMessage(Sender: TObject);
                     public
                           UserMessage : string;
                     public
                           function AddCtrl(thisCtrl: TCtrlHolder): integer;
                           procedure ReadRightsFromINI(const FileName: string);
                     public
                           constructor Create(const WithMessage: string = '');
                           destructor Destroy; override;
     end;// type TCtrlHolderList = class
The TCtrlHolder is just an intermediate class between the control(button in this case) and TCtrlHolderList which only holds the controls.
implementation
{ TCtrlHolderList }

function TCtrlHolderList.AddCtrl(thisCtrl: TCtrlHolder): integer;
begin
     thisCtrl.DeniedClick := DisplayDeniedMessage;
     Result := FCtrlList.Add(thisCtrl)
end;

constructor TCtrlHolderList.Create(const WithMessage: string = '');
begin
     FCtrlList := TList.Create;
end;

destructor TCtrlHolderList.Destroy;
var i : integer;
    tmp : TObject;
begin
     for i := FCtrlList.Count -1 downto 0 do begin
         tmp := FCtrlList[i];
         FreeAndNil(tmp);
         FCtrlList.Delete(i);
     end;//for i := FCtrlList.Count -1 downto 0 do begin
     FreeAndNil(FCtrlList);
end;

procedure TCtrlHolderList.DisplayDeniedMessage(Sender: TObject);
begin
     if UserMessage <> EmptyStr then
        MessageDlg(UserMessage, mtWarning, [mbOk], 0)
     else
         MessageDlg('Access denied', mtWarning,[mbOK], 0);
end;

procedure TCtrlHolderList.ReadRightsFromINI(const FileName: string);
var ini : TIniFile;
    i : integer;
    s : string;
begin
     ini := TIniFile.Create(FileName);
     for i := 0 to FCtrlList.Count -1 do begin
         s := ini.ReadString('rights', TCtrlHolder(FCtrlList[i]).Name, 'xxx');
         if s <> 'xxx' then
            TCtrlHolder(FCtrlList[i]).SetEnable(StrToBool(s));
     end;// for i := 0 to FCtrlList.Count -1 do begin
     FreeAndNil(ini);
end;

{ TCtrlHolder }

constructor TCtrlHolder.Create(onButton: TButton);
begin
     Obj := onButton;
     Name := Obj.Name;
     AllowedClick := Obj.OnClick;
     if not Obj.Enabled then
        Obj.OnClick := DeniedClick;
end;

procedure TCtrlHolder.SetEnable(T: boolean);
begin
     Obj.Enabled := T;
     if T then
        Obj.OnClick := AllowedClick
     else
         Obj.OnClick := DeniedClick;
end;
The idea is very simple and elegant, you only assign an event based on the rights, no conditions in the real OnClick event.
A demo application can be downloaded from this link(only source code is provided).

Friday, November 6, 2009

Lightning fast math expression evaluator

A few days ago I found a very fast and very well structured math expression evaluator which is actually a compiler, it is called Pegtop Delphi Math Component Library and can be found http://www.pegtop.net/delphi/components/math/download.htm.
Output of expression sin(sqrt(sqr x + sqr y)*7) /7
fldcw word ptr [esi+10]
fld qword ptr [esi+00]
fmul st(0), st(0)
fstp qword ptr [esi+20]
fld qword ptr [esi+08]
fmul st(0), st(0)
fadd qword ptr [esi+20]
fsqrt
fstp qword ptr [esi+28]
fld qword ptr [esi+30]
fmul qword ptr [esi+28]
fsin
fstp qword ptr [esi+38]
fld qword ptr [esi+40]
fdivr qword ptr [esi+38]
ret
(42 bytes)
Nice huh?

C like JIT interpreter in Delphi

Are you in need of a freeware fast C like JIT interpreter?
Look no further I present to you BeRoScript, it's created by Benjamin Rosseaux a.K.a. "Bero" and can be downloaded from this link, if link is broken then contact Benjamin directly, I'm sure he will send it to you.
Here's a taste of BeRoScript language from demo files provided with interpreter
File: prime.bs(prime number)
int main() {
 long i,k,gefunden=0;
 for (i=2;i<=2048;i++) {
  byte prime=1;
  for (k=2;k<=i;k++) {
   if (i!=k) {
    if ((i%k)==0) {
     prime=0;
     break;
    }
   }
  }
  if (prime) {
   printf(i," ist eine Primezahl\r\n");  
   gefunden++;
  }
 } 
 printf(gefunden," Primezahlen im Zahlenbereich 2 bis 2048 gefunden!\r\n");  
}
File: oop.bs(object oriented programming)
enum Geschlechter { maennlich=0, weiblich }
object Mensch {
 string Name;
 int Alter;
 int Geschlecht;
};
object Ort {
 string Adresse;
};
object Schule(Ort) {
 string Form;
};
object Lehrer(Mensch,Schule) {
 string Fach;
};
object Schueler(Mensch,Schule) {
 bool IstGut;
};
int Mensch::EineZahl() {
 return 1234;
}
void Mensch::printdata() {
 printf("Name: ",Name,"\n");
 printf("Alter: ",Alter,"\n");
 printf("Geschlecht: ",Geschlecht?"weiblich":"maennlich","\n");
}
void Ort::printdata() {
 printf("Adresse: ",this->Adresse,"\n");
}
void Schule::printdata() {
 inherited();
 printf("Schulform: ",this->Form,"\n");
}
void Lehrer::printdata() {
 inherited Mensch();
 inherited Schule();
 printf("Unterrichtet: ",Fach,"\n");
 printf(inherited Mensch.EineZahl()*2,"\n\n");
}
void Schueler::printdata() {
 inherited Mensch.printdata();
 inherited Schule.printdata();
 printf("Status: ",this->IstGut?"liefert gute Leistungen":"ist super faul","\n");
 printf(inherited EineZahl(),"\n\n");
}
void main(){
 Lehrer HerrMustermann;
 Schueler Max;
 HerrMustermann.Name="Tom Mustermann";
 HerrMustermann.Alter=38;
 HerrMustermann.Geschlecht=maennlich;
 HerrMustermann.Adresse="Musterstrasse 123";
 HerrMustermann.Form="Gesamtschule";
 HerrMustermann.Fach="Mathematik";
 Max.Name="Max Schmidt";
 Max.Alter=18;
 Max.Geschlecht=maennlich;
 Max.Adresse="Musterstrasse 123";
 Max.Form="Gesamtschule";
 Max.IstGut=true;
 HerrMustermann.printdata();
 Max.printdata();
} 
File: Zahlenrate.bs(pay rates)
int main() {
 printf("BeRoScript Zahlenraten - Version 1.00\n");
 printf("Copyright (C) 2004, Benjamin Rosseaux\n\n");
 printf("Gib deinen Namen ein: ");
 string name=trim(readstring());
 if(length(name)==0)name="Unbekannter";
 readln();
 printf("\nAlso ",name,", bist du fuers Spiel bereit? ;)\n\n");
 nochmal:
 int meinezahl,zahl=1000,versuche=10;
 bool gewonnen=false;
 unsigned char taste;
 meinezahl=round(random()*100);
 printf("Du muss nun eine Zahl zwischen 0 und 100 erraten! (-1=Ende)\n");
 printf("Du hast 10 Versuche!\n\n");
 while((meinezahl!=zahl)&&(zahl>=0)&&(versuche>0)){
  printf("Gebe deine Zahl ein: ");
  zahl=readint();
  if(versuche>1){
   if(zahl<0){
    break;
   }else if(meinezahlzahl){
    printf("Meine Zahl ist groesser\n");
   }else{
    printf("\nRichtig, ",name,"! Meine Zahl war ",zahl,"\n\n");
    gewonnen=true;
    break;
   }
  }
  if(--versuche){
   if(versuche==1){
    printf(name,"! Du hast nur noch einen einizigen Versuch!\n\n");
   }else{
    printf("Du hast noch ",versuche," Versuche!\n\n");
   }
  }
 }
 if(!gewonnen){
  printf("\nDu hast leider verloren! Meine Zahl war ",meinezahl,"\n\n");
 }
 readln();
 falscheeingabe:
 printf("Nochmal? (j/n)");
 taste=readchar();
 switch(taste){
  case 'j':case 'J':printf("\nOh, yeah ;)\n\n");readln();goto nochmal;
  case 'n':case 'N':printf("\nSchade, ja denn, bis bald, ",name,"! ;)\n");readln();break;
  default:printf("\nUps, falsche Eingabe ;)\n\n");readln();goto falscheeingabe;
 }
}

Blogroll(General programming and Delphi feeds)