A first look at the code

After uncompressing the rar file, I created several directory and I moved the files according to their types: all source code files went to src directory, all the executables files to exe directory. Then lib, obj and other common extensions.

The software is a multi-company multi-year accounting package, the type used by accounting professionals. Each company/year has a dedicated directory, under a root directory. Data files can be in the root directory if they are valid for every company (for example fiscal deadlines, vat codes) or in the subdirectory (invoices, clients, payments…). If the data file is present in both directories, the subdirectory has precedence.

Code has a mix of spaces and tabs (but not always); it uses # instead of !=; SELE instead of SELECT, RETU instead of RETURN (and so on). Remark blocks are delimited by a strange combination of /* that makes my editor choke sometimes on syntax highligting. Single lines of remmed code are introduced by *– and again the editor doesn’t recognize them as remark lines.

Printing is supported natively only on dot-matrix printers and in the source you find something like

SET DEVICE TO PRINTER
@ y,x SAY "text"

My hope was that they were using some sort of library for printing so that I could replace it if it was not available for Harbour. Since I don’t want to touch code that makes calculations (and business and presentation code is mixed in the source code) I will accept the idea to print to a temporary file and then use an external program to convert it to PDF, as suggested in harbour-users mailing list.

In the directory I found one batch file that compiles all the source files, one by one, using a long series of

CLIPPER file.prg -l

command. This batch file compiles 178 files. But in the src directory I now have 201 prg files. And some of the 178 files are not present among the 201! More on this later.

There are 17 .lnk files. They are in blinker syntax and they can be easily converted to hbmk2. From these files I understand that the software uses Funcky library. It also uses an internal library. I know the company had several business software and probably they share a common library… unfortunately the source code for this library is not present.

The software is composed by various executables – probably not 17, but I think at least 10. They call each other using a batch file: the program that wants to call another one sets the errorlevel and exits. The batch file then calls the appropriate executable depending on the errorlevel value. In the batch file the first executable shows the menu and has also a lot of forms inside but not the main ones.

To complicate a bit the situation, the first exe called by the batch file, as first step, asks the user to choice a working directory: all the following executables will have their curdir() in that directory. An environment variable will tell the software which is the root (where the exe and the common files are). So we have the current working directory set to a subdirectory, a root directory, and the need to set the working directory in a way that is kept between executable calls. The software uses Funcky chdir() function, in Harbour I could not find an equivalent function that keeps the changed directory after exiting the program.

Browsing the code, I think that the programmer had cobol roots. I never used cobol myself but I could recently have a look at some cobol source code. I found it redundant. The programmer was smart, but not very used to Clipper. There is not a single #include in the 201 source code files! One file, included and run at the beginning of each executable, has a long list of PUBLIC variables named after common #define constants and values assigned to them… there are also copyright lines from Clipper include files! As an example:

PUBLIC K_INS
K_INS        =   22     && Ins, Ctrl-V

Now K_INS is a public variable and its value can, by error, be modified. And 22 can be changed in a different Clipper release… The same happens for DBedit, aChoiche and other constants.

I decided to try to compile the main program. The batch file told me which one is the first called and a quick look confirmed that it had the menu inside. The menu is implemented… well… let’s just say “implemented”. I have never seen code so strange: as I said, the original programmer was very smart and infact implemented something that really worked but it was not really Clipper.
Located the proper blinker .lnk file, I manually converted it to hbmk2 .hbp format, listing all the files. The compiler failed in a couple of places for some incompatibility with Clipper (more on this later) and I promptly modified the code until it compiled with no errors.

Obviously linking failed with several missing functions, some of them from Funcky library but some also from the library I don’t have sources.

Time to make up a strategy: what to do with the missing functions? What to do with the multiple executables? What about the mix of root/subdirectory? In the next posts, of course :-)

A Christmas gift

I’ve been given a gift this Christmas. A rar compressed file containing 782 files.

It’s the directory used to build an old Clipper software, whose development started more than 20 years ago in Clipper 87 and is still in use by a couple of companies.

One of the two is a company operated by a friend of mine. About 17 years ago I created a program to export data from my friend “ERP” to be imported in this one. Both were clipper-based and the software had an import function in place. Unfortunately not all the infos we needed to move were imported by the procedure so I did some “tricks” (with developers knowledge, guidance and approval): I went directly to the DBFs, searching and adding records. The only drawback was that the user had to force a reindex. Not bad. This system has been working for years…

This old version of the application has been retired, the developers said (a couple of years ago) that they were not going to support it or develop new features to it. All the codebase was rewritten (ported?) in a completely new language and using a SQL database.

Unfortunately the import procedure that is present in the new version doesn’t cover all my friend needs and I can’t use the trick to directly add to the data tables. The developers can’t add these new functionality in a short time…

Just to complicate the situation, my friend company is updating the hardware and switching to Windows 7 64 bit. The old Clipper 87 software is not going to work on that workstations.

So, during a meeting, I just said that perhaps it would be possible to port the software to Harbour and at the same time solve the 64 bit problem and update the printing system that now needs a dot matrix printer. The answer was a “let us think about it” and I interpreted it as a “no”.

Some days later, just before Christmas, I found a mail with the rar file in the mailbox.

Back to the gift.

The rar file is just one directory that includes everything to build the executables and support them, including dbase III+, clipper and blinker, libraries, object files, batch files and of course source files.

I’d like to document somehow the porting of this app from Clipper 87 to current Harbour; I can’t name the software nor post its source code or screenshots, but I think that publishing some lines may be ok.

Debugging hbQt

I decided to spend some time trying to understand what is happening inside hbQt in certain situations.
I started with a fresh Harbour and hbQt build, compiled according to my previous post.

Harbour includes a way to trace code execution. You to enable it before compilation and before running a program setting some environment variables.

As usual, I created a new batch script in c:\cvs directory taking infos from readme.md

set HB_TR_LEVEL=always
set HB_TR_SYSOUT=yes

When we compile a source code inside Harbour and HB_TR_LEVEL is set, some #defines are read and code is compiled. When is not set, the code is simply ignored. We will see later some examples.

There are several levels of trace severity.

To look at the logs you need to run this software:
Download DebugView (http://technet.microsoft.com/it-it/sysinternals/bb896647.aspx).

We built a version of Harbour and hbQt without setting that env variables. When compiling hbQt the build process creates lots of intermediate c++ files in a parallel directory tree starting at addons\hbqt\.hbmk\win\mingw.
If we enter the hbqtgui subfolder you will see the generated files. They are named after the equivalent Qt classes.

If we run another build of qtcontribs, the files are not generated but hbmk2 checks if they are newer than the compiled file and, if yes, it compiles them.
So we can edit any .cpp file of hbqt and run hbmk2 qtcontribs.hbp to generate a new lib file with the updated function.
To shorten compilation time it is also possible to disable in qtcontribs.hbp all the libraries and utilities I’m not going to change.

I’m a command-line guy, and use vim as my editor. So I end having 3 command prompt windows:
– path set to the dir of the program used to test
– path set to the subdir of hbqt that I need to change (hbqt\qtcore for modifying internal hbQt files, hbqt\.hbmk\win\mingw\hbqtgui for testing the objects)
– path set to addons dir, to be able to issue hbmk2 qtcontribs.hbp
All three command prompt windows have se trace variables set
A fourth window is DebugView.

How to enable traceing in source code?

It is possible to enable tracing level by level, but to be honest I always find some problems to do so.
hbQt has a lot of trace messages at HB_TR_LEVEL=debug and enabling that level will bring a lot of logs that I’m not interested in.
So I use another method: I change the level in the lines I’m interested to trace from HB_TR_DEBUG to HB_TR_ALWAYS, so that I can have the logs of the lines I want to look for.

In cpp code the syntax is:

HB_TRACE( HB_TR_ALWAYS, ( "............QT_DESTROY_ENDS...............%p %p", qtObject, qObject ) );

It follows printf syntax to replace %p (pointers) %i (integers) %s (strings). Note that the strings and the values are enclosed in a parenthesis.

In Harbour the syntax is:

#include
...
HB_TRACE( HB_TR_ALWAYS, "value to trace "+str( value,5) )

Remember to set the environemnt variables in the command prompt windows to enable tracing, compile what you need, run DebugView and then run the test program.

A glimpse of future – hbdbu on android

Just to confirm that it is possible to run a Harbour application using QtContribs on android I post a screenshot taken from my Nexus mobile.

Not one line of QtContribs (hbqt/hbdbu/harbour) has been modified to build the android version.

Some changes may be needed since message boxes are implemented natively and don’t support html code… pressing the (i) button shows html text….

screenshot of hbdbu running on Android

 

In the third part of the series I will describe how to build hbdbu for android. Pritpal is also creating a tutorial: we share the same goal but we are taking different roads.

Please also keep in mind that Qt5.2.x and Qt5.3 BETA have problems with latest Android SDK so if you are following Pritpal tutorial and want to deploy to the virtual device you will probably need to set the enviroment variable

ANDROID_TARGET_ARCH     default/armeabi-v7a

If you want to deploy to a real device, you probably need to unset it.