The Hello Program Gallery


There is nothing that illustrates the workings of various operating systems and languages more than the "hello" program. The reason is simple: It is the minimum complexity program that does something verifiable (prints "hello, world"). You can reliably take hello as the minimum complexity program needed to gain access to a new system.

The hello program is the first example I create for any new operating system in Pascal, using the native interface for it (nowadays usually taking the C provided example and rewriting it in Pascal). The hello example program is famous for blowing up in size on various windowing operating systems.

So, lets do the example hello program in IP Pascal !


The hello program

 

program hello(output);

 

begin

 

   writeln('hello, world')

 

end.


Hello compiled and run in serial (command line) mode

 

 

Well, that's hardly a surprise, hello in serial was always easy.

How about hello with Windows console management calls, ie., a full 2-d text surface ?


Hello compiled and run in Windows Console mode

 

 

Is that the same program ? Looks like it, doesn't it. But it is not. Instead of outputting to Windows via serial file output calls, we are now talking via the console management interface, with full control over text positioning and color. So of course the program got more complex, right ? Here it is in console mode.


The hello program, in console mode

 

 

program hello(output);

 

begin

 

   writeln('hello, world')

 

end.

 

 

Ok, that was the same program. I just had to change the output library it was linked to, a single library name, now it's a console task. It isn't even necessary to recompile it.

Lets do something more complex, like hello in full graphical window under Windows.


Hello compiled and run in Windows graphical mode

 

 

Ok, that's a bit different. Now it clearly is not running in a console, but a graphical window. There is no command line, no prompt. But the result is pretty much identical.

Now, what is the new, more complex program required to get into graphical mode ? Something tells me you know the answer already.


The hello program, in Windows graphical mode

 

 

program hello(output);

 

begin

 

   writeln('hello, world')

 

end.

 

Yea, same program. And just as in the console mode application, I didn't even have to recompile, just relink with one library change.

One interesting feature of the IP Pascal Windows graphical library is evident above. Programs that terminate under Windows after just printing output normally terminate, don't they ? The library knew that the program was using the old fashioned exit because it self terminated without asking for any event information. So the library figures you need to see the "legacy" output and takes over after the program exits, then really exits when you order that via the Windows close button, or even old fashioned CNTRL-C.


Alright, all we have proven is that we can emulate older programs in console and graphical modes. That's not new. The problems with emulators to bring "old" programs forward are:

 There is only one way to answer all that. Lets move on.


Ok, lets go back and start taking advantage of each new interface as we move up from serial, to console, to graphical mode.

For console mode, we'll:

 Clear the screen to a different color.

 


"flashy" Hello compiled and run in Windows console mode

 

 

 


"flashy" Hello program, in Windows console mode

 

 

program hello(input, output);

 

uses trmlib;

 

var er: evtrec;

 

begin

 

   bcolor(output, green);

   fcolor(output, blue);

   curvis(output, false);

   page(output);

   cursor(output, maxx(output) div 2-12 div 2, maxy(output) div 2);

   writeln('hello, world');

   repeat event(input, er) until er.etype = etterm

 

end.

 

Now, we needed to add eight lines of program text (nonblank) to get the five new features. The first is the "uses" line, required because we are no longer just using standard Pascal features, but the custom procedures and functions implemented by the console library. Then, we needed to set both the foreground and background colors, set cursor invisible, and clear the screen. The cursor location (even though invisible) is set to the middle of x and y in the screen, with x offset 1/2 the string length to center the output string correctly. Finally, an event loop is added to capture the termination event, which the console library takes from either a CNTRL-C entered or the normal windows "close" button, or even a interprocess message such as a system wide kill for power down.

 Now note that we have not changed any of the original statements, we have just added new ones to get the required features. Second, note that the output is still being done with standard output constructs from Pascal. The screen is even cleared with a standard "page" procedure.

 Note that this time, we don't get the automatic "finished - ..." titlebar of the first console hello. The library knows we are handling the exit from the window without being told.

Now, by any chance with this all also work with a graphical window ?

 


"flashy" Hello compiled and run in Windows graphical mode

 

 

Yes, it's the exact same program, I'm going to spare you a new listing of it. Just as before, its just a new link, not a full recompile. Only the name of the link library needed changing.

 And here I can illustrate the point. Graphical mode is fully upward compatible with text mode. And text mode was fully upward compatible with ordinary serial mode, and that is fully compatible with the ISO 7185 Pascal standard. This is not just done by careful programming on your part. You cannot write a program in serial mode that is not compatible with text and graphical mode, and you cannot write a program in text mode that is not compatible with graphical mode.

 Alright, lets finish up by seeing what we can add in graphical mode that we could not get in text mode. How about:

 


Graphically enhanced "flashy" Hello compiled and run in Windows graphical mode

 

 

Ok, so the colors are nothing to write home about. Now for the code.


"flashy" Hello program, in Windows console mode

 

program hello(input, output);

 

uses gralib;

 

var er: evtrec;

 

begin

 

   bcolor(output, green);

   curvis(output, false);

   auto(output, false);

   page(output);

   fcolor(output, red);

   frect(output, 50, 50, maxxg(output)-50, maxyg(output)-50);

   fcolorg(output, maxint, maxint-(maxint div 3), maxint-maxint div 3);

   frect(output, 50, 50, 53, maxyg(output)-50);

   frect(output, 50, 50, maxxg(output)-50, 53);

   fcolorg(output, maxint div 2, 0, 0);

   frect(output, 52, maxyg(output)-53, maxxg(output)-50, maxyg(output)-50);

   frect(output, maxxg(output)-53, 52, maxxg(output)-50, maxyg(output)-50);

   font(output, font_sign);

   fontsiz(output, 100);

   binvis(output);

   fcolor(output, cyan);

   cursorg(output, maxxg(output) div 2-strsiz(output, 'hello, world') div 2+3,

                   maxyg(output) div 2-100 div 2+3);

   writeln('hello, world');

   fcolor(output, blue);

   cursorg(output, maxxg(output) div 2-strsiz(output, 'hello, world') div 2,

                   maxyg(output) div 2-100 div 2);

   writeln('hello, world');

   repeat event(input, er) until er.etype = etterm

 

end.

 

Now in this program, you will see that a lot of the position calls and functions have an added "g", like "cursorg", "maxxg", etc. We have changed from character to pixel coordinates and sizes. The character coordinates and sizes are still there, but they no longer have the granularity we need. Also, when we use proportional fonts like the "sign" font, only the character heights have meaning. The character widths are in fact valid only for the "space" character, which means not that useful.

 A new feature is the "auto" procedure, which in fact turns off automatic scrolling. A quirk of the graphical library is that it does not like to switch to proportional fonts unless that feature is off, because proportional fonts make the line ending vary according to the characters on the line.

We drew the beveled edge box the "hello, world" text sits on with a series of filled rectangle calls. Text mode only knows the whole colors red, green, blue, cyan, magenta and yellow, but graphical mode knows the full range of RGB (Red-Green-Blue) values, but notice that we started with a text mode color set to red, then went to the graphical RGB color version of the fcolorg call. The actual values of each R, G, and B are not fixed integers, but are "scaled to maxint", meaning that maxint is the full value of the color, and 0 is dark. We do that because the range of RGB values is in the process of going up as graphical card manufacturers deliver more and more powerful video cards. With scaled RGB numbers, our programs will never go out of date.

 Next, the font itself is selected with a virtual font number "font_sign", or the sign font. The sign font is just a placeholder for "general purpose sans serif" font. And sans serif is generally what you see on signs, especially freeway signs. We set the size of the font in pixel height. Finally, we set the background "invisible" with binvis. The reason for that is that, in text mode, each character is a fully drawn box, both under the character and the face of the character itself. Removing the background means we can overdraw any other figure with a character.

 Next, we draw the "hello, world" string in a very similar way as the previous text programs, except that the positioning is to the pixel and not the character. Also, we first drop a cyan "shadow" of the text offset 3 pixels to the right and down of the actual string to create the drop shadow. Then we overwrite the drop shadow with the actual text in blue.

 Notice that we had to remake very little of the program to get this far. The biggest change was going from character coordinates and sizes to pixel coordinates and sizes, but this was not bad, since we were treating them as proportions anyway.

 Now this program also illustrates a point. Drawing drop shadows should be a routine if we use it much, and so should beveled boxes, etc. The point is that the basic graphical library does not try to implement every single tricky graphical object you might want to use. Instead, the function set of the library is kept quite small by considering if a new call might be created with other, existing functions. If so, it is better left to an extension library set of calls. This clearly separates the essential core library from the widget collection libraries I provide.


Hello to the METAL

 

Alright, maybe you read this, and said "That's interesting. But I don't plan to ever implement my program anywhere but Windows. I want to go direct to the windows interface, without any software layers between me and Windows. I want speed, and I want full use of the Windows call catalog".

 Well, there is actually a big service that IP Pascal can provide you that you didn't realize. More about that in a minute. Here's your program.


Hello written for, compiled and run in Windows graphical mode

 

 


Hello program written directly for Windows graphical mode

 

{******************************************************************************

*                                                                             *

*                        HELLO FOR WINDOWS                                    *

*                                                                             *

* This program displays a hello message centered in the middle of a window.   *

* It is a direct Pascal translation of the hellowin program given in          *

* "programming windows" by Charles Petzold.                                   *

*                                                                             *

******************************************************************************}

 

program hellow;

 

uses windows;

 

var wc:   sc_wndclassa; { windows class structure }

    wh:   integer;      { window handle }

    msg:  sc_msg;       { message holder }

    r:    integer;      { result holder }

    b:    boolean;      { boolean result holder }

    v:    integer;

 

{ function places a string in dynamic storage }

 

function str(view s: string): pstring;

 

var p: pstring;

 

begin

 

   new(p, max(s));

   p^ := s;

   str := p

 

end;

 

function wndproc(hwnd, imsg, wparam, lparam: integer): integer;

 

var hdc:  integer; { handle to device context }

    ps:   paint;   { paint structure }

    rect: rect;    { rectangle holder }

    b:    boolean; { result holder }

    r:    integer; { result holder }

 

begin

 

   if imsg = wm_create then begin

 

      r := 0

 

   end else if imsg = wm_paint then begin

 

      { perform paint cycle }

      hdc := BeginPaint(hwnd, ps);

      b := GetClientRect(hwnd, rect);

      r := DrawText(hdc, 'Hello from Pascal Windows !!', rect,

                    DT_SINGLELINE or DT_CENTER or DT_VCENTER);

      b := EndPaint(hwnd, ps);

      r := 0

 

   end else if imsg = wm_destroy then begin

 

      postquitmessage(0);

      r := 0

 

   end else r := defwindowproc(hwnd, imsg, wparam, lparam);

 

   wndproc := r

 

end;

 

begin { main program }

 

   v := $80000000;

   { set windows class to a normal window without scroll bars,

     with a windows procedure pointing to the message mirror.

     The message mirror reflects messages that should be handled

     by the program back into the queue, sending others on to

     the windows default handler }

   wc.style      := cs_hredraw or cs_vredraw;

   wc.wndproc    := wndprocadr(wndproc);

   wc.clsextra   := 0;

   wc.wndextra   := 0;

   wc.instance   := getmodulehandle;

   wc.icon       := loadicon(idi_application);

   wc.cursor     := loadcursor(idc_arrow);

   wc.background := getstockobject(white_brush);

   wc.menuname   := nil;

   wc.classname  := str('stdwin');

   { register that class }

   b := registerclass(wc);

   { create the window }

   wh := createwindowex(

            0, 'stdwin', 'Hello', ws_overlappedwindow,

            v{cw_usedefault}, v{cw_usedefault},

            v{cw_usedefault}, v{cw_usedefault},

            0, 0, getmodulehandle

         );

   { present the window }

   b := showwindow(wh, sc_sw_showdefault);

   { send first paint message }

   b := updatewindow(wh);

   { message handling loop. Since messages are reflected, we do all

     message handling here instead of sending them on to the windows

     procedure as normal }

   while getmessage(msg, 0, 0, 0) do begin { not a quit message }

 

      b := translatemessage(msg); { translate keyboard events }

      r := dispatchmessage(msg);

 

   end                  

 

end. { main program }

 

Ok, so here we go, we are talking directly to Windows now, right ? Well, no. Actually Windows "talks" in C, not Pascal. You'll note that we are passing strings like the one in "createwindowex". In many Pascal versions out there, calling C routines is done by allowing a lot of C type language functions into Pascal, like taking the address of variables, zero terminated strings, etc. And with most operating systems coded in C, we have to live in a C centered world.

But allowing a lot of C type operators into Pascal also compromises its type security. IP Pascal uses a better way. The reason you have to use such features in a Pascal program is so you can (manually) translate Pascal types into C types (and back) in your program. The C calls could very well have been specified in Pascal form, and then there would be no problem. IP Pascal circumvents the problem by constructing a short "translation layer", in assembly language, which takes Pascal formatted calls and changes them to C calls to the operating system, and changes the results back to Pascal formatted data.

The result is you get better type security than the "make Pascal look like C" way, and its less work for you, since you aren't coding the conversions into your program. The result is a cleaner program as well. The drawback is that IP Pascal has to do all the work to create the translation layer. But that is not a drawback for you, is it ? :-)


 For more information contact: Scott A. Moore samiam@moorecad.com