FoxPro to Harbour...

1,107 views
Skip to first unread message

Michael Green

unread,
Jan 4, 2017, 8:01:47 AM1/4/17
to Harbour Users
I have now converted most of my FoxPro applications into Harbour code. 
This is an updated list of the problems I had and how I solved them : 

Installing Harbour in FreeBSD.

First 'pkg search harbour' then 'pkg install harbour'. As indicated by the installation 
message from bash, edit /etc/fstab, add 'fdesc /dev/fd fdescfs rw 0 0'

Using Harbour

Simple as '$ hbmk2 filename.prg'. You don't even need the '.prg' ending, BUT the
top level file has to have 'proc main()...return' in it or you will get a compile time error.


Compile time errors 

1. ; (line continuation chr) in text areas. Move semicolons out of 
text areas. 

2. Differences in array syntax. Dimension to private, round brackets 
to square. 
Example: 
dime arrayv(3,5)    && FoxPro 
private arrayv[3,5]  && Harbour 

3. recno(0) (Fox) vs set softseek on (Harbour). Note 'seek <memvar> softseek' also works.

4. 'Display' doesn't need the 'fields' clause. 

5. 'Browse' not supported, use browse(). 

6. Scroll command not supported. Use scroll() 

7. Errors in the form " undefined reference to `HB_FUN_TREATV'" mean 
that Harbour cannot find a udf named treatv(). Typically this will be 
because a FoxPro array variable hasn't been reformatted. 
So, for instance, a line still has 
treatv(blah, blah), rather than treatv[blah, blah]. Also the FoxPro 
sys() functions will all trigger this (HB_FUN_SYS). 
Use grep to identify the file ($ grep -ly 'treatv(' *.prg ), then edit 
the file indicated and use the search function to find the missed 
array name. 

8. Sys(2) = seconds(). Seconds() return numeric, sys(2) returns 
character, so val(sys(2)) = seconds(). 

9. Sys(2002) = set cursor off. 

10. Sys(2002,1) = set cursor on. 

11. No scatter/gather in Harbour, you have to make your own:

&& udf scatter() &&&&&&&&&&&&&&&&&&&&&&&&&&&
function scatter
&& create a variable that gather() will be able to see
public scatgatav[0]
&& store dbf structure for current work area to array
store dbstruct() to scatgatav
&& loop throught array storing values from current record
store 1 to countv
do while countv < fcount()+1
   store fieldget(countv) to scatgatav[countv]
   store countv+1 to countv
enddo
return .t.

&& udf gather() &&&&&&&&&&&&&&&&&&&&&&&&&&
function gather
&& replace values into current, locked record
store 1 to countv
do while countv < fcount()+1
   fieldput(countv, scatgatav[countv])
   store countv+1 to countv
enddo
return .t.

So adding the UDFs above means that 'scatter()' replaces 'scatter to <memvar>' and
'gather()' replaces 'gather from <memvar>'.

12. 'Set printer to lp -dprinter' doesn't work. Harbour assumes it is a print file and adds '.prn.' to the end.
Change to 'set printer to output' then, after closing, send 'output.prn' to the printer with an OS level command:
'! lp output.prn'. Add a short delay to prevent later print commands overwriting output.prn. For example inkey(3).

13. Str(). when using str(numeric_variable) always use the length parameter ie: store str(numvar,5) to thingv, 
because the defaults are different in FoxPro.

14. In some places parenthesis () substitutes for macro & . For example 'use (filenamev)'

15. Ascan() doesn't work on two dimensional arrays in Harbour, or at least not the same way FoxPro works. Use two arrays.


Run time errors 

1. Permissions problems can cause hard to understand error messages. 
'# chmod a+rw *' is the way to go. Also add to a common group for all the users.

2. Memory variable (.mem) files aren't compatible, they have to be 
recreated. This doesn't seem to a a problem now (Harbour 3.0).


I hope this may help anyone who follows the same FoxPro to Harbour 
path. This is a very useful resource: http://harbourminigui.com/clipperng/index.php
If anyone notices something I missed feel free to reply. 

I've attached my rough-'n'-ready command line utilities for anyone to use and abuse.

Thanks to all who generously helped, especially to Massimo.
disp_stru.prg
disp_all.prg
disp_memfile.prg
create_memvar.prg
modi_stru.prg
browse_file.prg
create_dbf.prg

Mario H. Sabado

unread,
Jan 4, 2017, 8:12:31 AM1/4/17
to harbou...@googlegroups.com
Hi Michael,

Did you link also the hbfoxpro from the contrib? 

Regards,
Mario
--
--
You received this message because you are subscribed to the Google
Groups "Harbour Users" group.
Unsubscribe: harbour-user...@googlegroups.com
Web: http://groups.google.com/group/harbour-users

---
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to harbour-user...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Michael Green

unread,
Jan 4, 2017, 8:30:53 AM1/4/17
to Harbour Users


Did you link also the hbfoxpro from the contrib? 


I was not aware of hbfoxpro until I read you message. On a quick Google it looks interesting.  

Klas Engwall

unread,
Jan 4, 2017, 3:43:57 PM1/4/17
to harbou...@googlegroups.com
Hi Michael,

> 12. 'Set printer to lp -dprinter' doesn't work. Harbour assumes it is a
> print file and adds '.prn.' to the end.
> Change to 'set printer to output' then, after closing, send 'output.prn'
> to the printer with an OS level command:
> '! lp output.prn'. Add a short delay to prevent later print commands
> overwriting output.prn. For example inkey(3).

The ".prn" extension is added because set(_SET_DEFEXTENSIONS) is .T. by
default just like in Clipper. You can turn it off either for the entire
application (but that will also turn off adding ".dbf" and other default
extensions) or by wrapping your set printer to ... command:

lDefExt := set( _SET_DEFEXTENSIONS, .F. )
set printer to whatever
set( _SET_DEFEXTENSIONS, lDefExt )

Then you can put those lines in a UDF like this:

#include "set.ch"
function SetPrinterTo( cPrinter )
local lDefExt := set( _SET_DEFEXTENSIONS, .F. ) // Save & turn off
set( _SET_PRINTFILE, cPrinter ) // Equal to "set printer to"
set( _SET_DEFEXTENSIONS, lDefExt ) // Set it to previous setting
return NIL

and call it with:

SetPrinterTo( whatever )

Regards,
Klas

jgt

unread,
May 25, 2019, 2:13:20 PM5/25/19
to Harbour Users

i have been converting an application consisting of about 30 programs and 5000 lines on code from  Foxpro 2.6 for unix on SCO to Harbour 3.4 on Centos.  The original application was written in Foxbase and subsequently upgraded to Foxpro.
Besides the issues that Michael found, Harbour is case sensitive to database file names where Foxpro is not.  Standard Foxpro index files are not compatible with Harbour, but cdx (combined index files) are using the 'dbfcdx' driver.  I also found some differences in the location of the file pointer after a partial key seek. Foxpro puts the pointer at the beginning of the sequence, where Harbour puts it at the end.
 
i have not as yet found a substitute for sys(31) which retrieves the result status of a run command.
Bash
[code]
$cat ABC >test.txt
$grep A test.txt
?echo $?
[/code]
Foxpro
[code]
run "grep A test.txt"
rstatus=sys(31)
?rstatus
[/code]

By the way, I budgeted 100 hours to change the programs, and found that some took as little as an hour, and others took over a day.  For perspective, i had almost zero experience with Harbour or Clipper, and over 25 years with Foxpro.

Jack

Klas Engwall

unread,
May 25, 2019, 3:51:09 PM5/25/19
to harbou...@googlegroups.com
Hi jgt,

> i have been converting an application consisting of about 30 programs
> and 5000 lines on code from  Foxpro 2.6 for unix on SCO to Harbour 3.4
> on Centos.  The original application was written in Foxbase and
> subsequently upgraded to Foxpro.
> Besides the issues that Michael found, Harbour is case sensitive to
> database file names where Foxpro is not.

No, but file names in *nixes are case sensitive, and Harbour just passes
your file name string to the OS. Maybe FoxPro hides that difference
between *nix and Windows somehow?

I had a quick look at Michael's report and noticed that not all his
observations are correct. For example, item #15, ascan() is very
powerful with any number of array dimensions. See
http://www.ousob.com/ng/53guide/ - I noticed that error in the report
because it was at the bottom of the list.

> Standard Foxpro index files
> are not compatible with Harbour, but cdx (combined index files) are
> using the 'dbfcdx' driver.  I also found some differences in the
> location of the file pointer after a partial key seek. Foxpro puts the
> pointer at the beginning of the sequence, where Harbour puts it at the end.

You are probably doing something unusual. I do not recognize what you
describe. Can you create a small self-contained example that shows it?

> i have not as yet found a substitute for sys(31) which retrieves the
> result status of a run command.
> Bash
> [code]
> $cat ABC >test.txt
> $grep A test.txt
> ?echo $?
> [/code]
> Foxpro
> [code]
> run "grep A test.txt"
> rstatus=sys(31)
> ?rstatus
> [/code]

The RUN command in Clipper and Harbour returns nothing, and there is no
Sys() function at all (but many other specific functions for different
needs instead). HB_ProcessRun() will return the result to the caller, so
use cResult := HB_ProcessRun( "grep A test.txt" ) instead of the RUN
command.

Regards,
Klas

jgt

unread,
May 27, 2019, 12:46:52 PM5/27/19
to Harbour Users

Klas,

Foxpro source code can be written in either upper case or lower case so:

USE CUSTMAST IN 0
will find the same external file as
use cusmast in 0.
In both cases the program looks for custmast.dbf in the default path.
Where this became a problem for me is that over a 30 year period only two programmers have worked on the application, and we decided that he would write all his code in upper case and i would use lower case.

Another difference:
Foxpro
use custmast in 0
seek cust_from_input
use artrans in 0
select artrans
seek custmast.custno
if found()
do while artrans.custno = custmast.custno .and. .not. eof()
?invno+str(amount)
skip 1
enddo

Harbour
custmast='custmast'
artrans='artrans'
use custmast alias custmast
use artrans alias artrans
select custmast
seek cust_from_input
select artrans
seek custmast->custno
if  found()
do while artrans->custno = custmast->custno .and. .not. eof()
?invno+str(amount)
skip 1
enddo


 I am still working on how to demonstrate the file pointer issue.
Jack

S E

unread,
May 27, 2019, 2:01:59 PM5/27/19
to Harbour Users


On Monday, May 27, 2019 at 6:46:52 PM UTC+2, jgt wrote:


Foxpro source code can be written in either upper case or lower case so:

USE CUSTMAST IN 0
will find the same external file as
use cusmast in 0.
In both cases the program looks for custmast.dbf in the default path.

Probably you want to use SET FILECASE LOWER and maybe SET DIRCASE LOWER too.
It will bring all requested file names to something you expect. Harbour doesn't cover operating filesystem case sensitivity by default

If you're using Linux, you have to think about it. If you're using Windows or MacOS then it doesn't matter.

Regards
S.


jgt

unread,
May 18, 2021, 10:38:39 AM5/18/21
to Harbour Users
I had forgotten about this thread.   I did some experiments yesterday and found that the following works:
set printer to '|lp -s -ddestination'
Presumably Harbour print files can be piped into any program.

jgt

unread,
May 18, 2021, 10:47:26 AM5/18/21
to Harbour Users
Also:
Foxpro - index on field for field2 = literal to index_name
Harbour- index on field to index_name for field2 = literal
Foxpro allows:
index on alltrim(field) to index_name
Harbour fails if len(alltrim(field))=0

jan.sp...@grecoavalon.com

unread,
May 18, 2021, 1:50:35 PM5/18/21
to harbou...@googlegroups.com

Hi everybody:

 

I would like to ask if somebody has already written some JSON-to-XML function?

 

Tx in advance,

 

BR,

Jan Sperling

 

jgt

unread,
May 18, 2021, 3:53:37 PM5/18/21
to Harbour Users
In Foxpro, there is a function gomonth(date,num), where a new date is returned that is num months in the past or future:
so
?gomonth(ctod("05/18/2020"),-3)
02/18/2020
?gomonth(ctod("05/31/2020")-3)
02/28/2020
the absolute value of num can be greater than 12.
Is there a Harbour equivalent?

Mario H. Sabado

unread,
May 18, 2021, 5:56:07 PM5/18/21
to 'elch' via Harbour Users
Hi,

AddMonth() in Harbour should work the same as GoMonth().

Regards,
Mario

--
--
You received this message because you are subscribed to the Google
Groups "Harbour Users" group.
Unsubscribe: harbour-user...@googlegroups.com
Web: http://groups.google.com/group/harbour-users

---
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to harbour-user...@googlegroups.com.

jgt

unread,
May 18, 2021, 9:06:34 PM5/18/21
to Harbour Users
Thanks,
I decided to write it:
function gomonth
parameter idate, inum
set century on
year=year(idate)
mon=month(idate)
y=int(inum/12)
m=mod(abs(inum),12)
if inum <0
    m=-(m)
endif
newday=day(idate)
newmon=mon+m
newyear=year+y
if newmon>12
    newmon=newmon-12
    newyear=newyear+1
endif
if newmon <1
    newmon=newmon+12
    newyear=newyear -1
endif
if newmon = 04 .or. newmon=06 .or. newmon=09 .or. newmon=11
    if newday >30
        newday=30
    endif
endif
if newmon=02 .and. newday >28
    newday=28
    if mod(newyear,4)=0
        newday=newday+1
    endif
endif
outdate=strtran(str(newyear,4)+str(newmon,2)+str(newday,2)," ","0")
outdate=stod(outdate)
return outdate

Mario H. Sabado

unread,
May 18, 2021, 9:22:32 PM5/18/21
to 'elch' via Harbour Users
Or...

Function GoMonth(ldate,inum)
Return AddMonth(ldate,inum)



Reply all
Reply to author
Forward
0 new messages