Harbour Project and FlexFile3 FPT files

444 views
Skip to first unread message

F McKenney

unread,
May 12, 2014, 11:22:32 PM5/12/14
to harbou...@googlegroups.com

I'm still working to migrate the decompiled Clipper source for a last-century app forward so it will compile and run correctly under Harbour Project v3.2. Anyone else planning to do this should be aware that getting a clean compile-and-link is only half the job.

For example, the app I'm working with has five FPT files, which I understand are "memo" files related to DBF files.  Two of these have the string "FlexFile3" embedded in their header, the other three do not:

00000000  00 00 23 b5 00 00 00 40  00 00 00 00 00 00 00 00  |..#....@........|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200  46 6c 65 78 46 69 6c 65  33 03 00 00 40 e9 08 00  |FlexFile3...@...|
00000210  40 dd 08 00 25 d4 00 00  00 00 00 00 00 00 00 00  |@...%...........|
00000220  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000400  00 00 00 01 00 00 05 1c  49 6e 20 67 65 6e 65 72  |........In gener|

I've seen hints that Harbour Project supports FlexFile3 memo files, such as this comment in a ChangeLog file:

  2002-03-18 01:48 UTC-0300 Horacio Roldan
     * source/rdd/dbfcdx/dbfcdx1.c
       + added compatibility with Clipper 5.3 (FlexFile) memo headers
       bug reported by Walter Negro.


but I haven't found any specific documentation on this or what I need to do to turn this support on if it does exist.

After issuing this command:

  rddRegister("DBFCDX", 1)

my code can retrieve data from one of the FlexFile3 FPT files, but it... looks odd.  For example, in place of the usual 0D 0A CR/LF characters I see 8D 0A... but only sometimes.  This has the "feel" of some sort of compressed data not being properly decompressed, but I freely admit I'm guessing.

Here's my question: Are the contents of this file accessible using only what's provided with Harbour Project v3.2?

Or do I need to bite the bullet and order a copy of the FlexFile3 library from this site:

  http://www.grafxsoft.com/flex.htm

Unfortunately, it's not clear from the writeup there whether that library is even compatible with Harbour Project.  If anyone has used it with an application compiled using the Harbour Project compiler I would appreciate hearing from you.

And if I'm asking the wrong question ( which does happen sometimes ) please feel free to point that out as well. <grin!>


Frank McKenney
McKenney Associates

Klas Engwall

unread,
May 13, 2014, 6:11:04 PM5/13/14
to harbou...@googlegroups.com
Hi Frank,

> I've seen hints that Harbour Project supports FlexFile3 memo files, such
> as this comment in a ChangeLog file:
>
> 2002-03-18 01:48 UTC-0300 Horacio Roldan
> * source/rdd/dbfcdx/dbfcdx1.c
> + added compatibility with Clipper 5.3 (FlexFile) memo headers
> bug reported by Walter Negro.
>
> but I haven't found any specific documentation on this or what I need to
> do to turn this support on if it does exist.
>
> After issuing this command:
>
> rddRegister("DBFCDX", 1)
>
> my code can retrieve data from one of the FlexFile3 FPT files, but it...
> looks odd. For example, in place of the usual 0D 0A CR/LF characters I
> see 8D 0A... but only sometimes. This has the "feel" of some sort of
> compressed data not being properly decompressed, but I freely admit I'm
> guessing.
>
> Here's my question: Are the contents of this file accessible using only
> what's provided with Harbour Project v3.2?

Harbour is much more flexible than Clipper, so you can combine any type
of memo file with any type of RDD. But you may have to tell Harbour what
you want.

Przemek originally wrote most of the current RDD code for xHarbour, and
then it was imported to Harbour. That is why it can be difficult to find
RDD specific info in the Harbour changelog. A hint for finding info can
be to search all .txt files and .prg files in the Harbour tree for the
string "fpt" and even to do the same thing with the changelog files from
around nine or ten years ago for the xHarbour project.

I don't use memo files myself, so what I know about the subject comes
from reading about it. Anyway ... there is a separate RDD that inherits
from DBFCDX but uses FPT as the default memo type. The RDD name is
FPTCDX. It can be found in src\rdd\usrrdd\rdds\fptcdx.prg if you want to
take a look at it (since it inherits from existing RDDS it is only 76
lines long). Or you can set it up yourself something like this (if I
understood it correctly):

#include "dbinfo.ch"
REQUEST DBFCDX
REQUEST DBFFPT
rddInfo( RDDI_MEMOTYPE, DB_MEMO_FPT, "DBFCDX" )

(Przemek might jump im here and correct me :-) )

Searching further, I found this changelog entry in xHarbour's changelog.024:

//-----------------------------------------------
2005-09-11 21:30 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
[...]
Now DBFDBT RDD is no longer necessary and DBFFPT should work with
any memo files: DBT, FPT and SMT. Please test it.
On open memo type should be recognized automatically.
For newly created file type of MEMO can by set by:
rddInfo( RDDI_MEMOTYPE, DB_MEMO_DBT [, <cRdd> ] )
rddInfo( RDDI_MEMOTYPE, DB_MEMO_FPT [, <cRdd> ] )
rddInfo( RDDI_MEMOTYPE, DB_MEMO_SMT [, <cRdd> ] )
For FPT memo files also subversion can be set with:
rddInfo( RDDI_MEMOVERSION, DB_MEMOEXT_FLEX [, <cRdd> ] )
rddInfo( RDDI_MEMOVERSION, DB_MEMOEXT_SIX [, <cRdd> ] )
Default memotype in DBFCDX is FPT(FLEX) and in DBFNTX DBT.
DBFFPT is noe requested by default in RDDSYS() instead of
DBFDBT which is no longer necessary.
//-----------------------------------------------

Regards,
Klas

F McKenney

unread,
May 13, 2014, 10:41:59 PM5/13/14
to harbou...@googlegroups.com

Klas,

Thank you for jumping in.

On Tuesday, May 13, 2014 6:11:04 PM UTC-4, Klas Engwall wrote:

  [...]
 
Harbour is much more flexible than Clipper, so you can combine any type
of memo file with any type of RDD. But you may have to tell Harbour what
you want. 

"Aye, there's the rub."  <grin!>
 
Przemek originally wrote most of the current RDD code for xHarbour, and
then it was imported to Harbour. That is why it can be difficult to find
RDD specific info in the Harbour changelog. A hint for finding info can
be to search all .txt files and .prg files in the Harbour tree for the
string "fpt" and even to do the same thing with the changelog files from
around nine or ten years ago for the xHarbour project.

It's getting late, but I may try that tomorrow.
 
I don't use memo files myself, so what I know about the subject comes
from reading about it. Anyway ... there is a separate RDD that inherits
from DBFCDX but uses FPT as the default memo type. The RDD name is
FPTCDX. It can be found in src\rdd\usrrdd\rdds\fptcdx.prg if you want to
take a look at it (since it inherits from existing RDDS it is only 76
lines long). Or you can set it up yourself something like this (if I
understood it correctly):

#include "dbinfo.ch"
REQUEST DBFCDX
REQUEST DBFFPT
rddInfo( RDDI_MEMOTYPE, DB_MEMO_FPT, "DBFCDX" ) 

I've tried both approaches, and see the sme results as I did before: odd characters in the MEMOEDIT display.

Given your feedback, though, it sounds like my problem may not be in the MEMO field handling but in MEMOEDIT(), or the way this code invokes it.
 
//-----------------------------------------------
2005-09-11 21:30 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
[...]
    For FPT memo files also subversion can be set with:
       rddInfo( RDDI_MEMOVERSION, DB_MEMOEXT_FLEX [, <cRdd> ] )
       rddInfo( RDDI_MEMOVERSION, DB_MEMOEXT_SIX [, <cRdd> ] )
//-----------------------------------------------

That certainly sounds like it ought to be working. And, given my inexperience with Clipper/Harbour, it may even be working as expected.

I did a little more research this afternoon, and it appears that the 0x8D 0x0A sequence is, in Clipper terms, a "soft carriage return", and perfectly normal in a MEMOEDIT field. Likewise, the 0x0D 0x0A sequence is a "hard carriage return". What is odd, of course, is that these characters are being displayed rather than causing an action.

 0x0D  Musical note
 0x8D  "Washing machine"
 0x0A  Lowercase i accent grave

MEMOEDIT() is being invoked with a user-defined function with the remarkably unoriginal name of MEFN() that is intended to map the F2-F5 and Insert keys as follows:

  F2  Go to start of displayed text (like Ctrl-Home)
  F3  Go to end of displayed text (like Ctrl-End)
  F4  Go to start of MEMO string (like Ctrl-PgUp)
  F5  Go to end of MEMO string (like Ctrl-PgDn)
  Insert  Toggle insert mode, but also display state below window.

F2, F4, F5, and Insert behave as expected. F3 returns a ME_BOTTOMRIGHT code to MEMOEDIT(), which surprisingly exits MEMOEDIT rather than moving the cursor. Further, Ctrl-B, which the MEMOEDIT documentation implies should re-format the current paragraph (and possibly relocate a number of "soft CRs", simply advances the cursor to the beginning of the next word, like Ctrl-F/Ctrl-RightArrow.

Here's the invocation of MEMOEDIT():

  crv:= memoedit(fld, wm[2], wm[3], wm[4], wm[5], lwrite, "mefn")

where 'fld', of course, is the string being edited, wm[2-5] are the screen coordinates of the editing window, 'lwrite' is .T., and "mefn" is the UDF.

What I can't figure out for the life of me is what would make MEMOEDIT decide to display what would normally be considered control characters.

Hm. The contents of the MEMO fields were originally created by the 16-bit DOS/Clipper app whose decompiled (and thus uncomented) source I have been working with. How, exactly, does the Harbour implementation of MEMOEDIT() decide whether a given byte represents a displayable character or is a control character?

I suddenly realize that I've never checked to see how Clipper/Harbour handle CODEPAGEs and such, though it's far from clear why that would affect the MEMOEDIT editing keys. In any case, it sounds like a good place to start doing research... tomorrow. <grin!>

Thanks, Klas.


Frank

Alex Strickland

unread,
May 14, 2014, 5:32:58 AM5/14/14
to harbou...@googlegroups.com
On 2014-05-14 04:41 AM, F McKenney wrote:

> MEMOEDIT() is being invoked with a user-defined function with the
> remarkably unoriginal name of MEFN() that is intended to map the F2-F5
> and Insert keys as follows:

From long years of reading this list I would say memoedit() has a few
compatibility problems, and plain bugs. I don't use it myself.

--
Regards
Alex

Francesco Perillo

unread,
May 14, 2014, 6:24:30 AM5/14/14
to harbou...@googlegroups.com
Yes, it seems that memoedit is incomplete. I use as a text reader and it seems to work, but not as an editor.




--
--
You received this message because you are subscribed to the Google
Groups "Harbour Users" group.
Unsubscribe: harbour-users+unsubscribe@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-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Klas Engwall

unread,
May 14, 2014, 1:51:31 PM5/14/14
to harbou...@googlegroups.com
Hi Frank,

> Given your feedback, though, it sounds like my problem may not be in the
> MEMO field handling but in MEMOEDIT(), or the way this code invokes it.

Ah, MemoEdit() ... see Alex' and Francesco's responses. It seems to be a
function (or a class, really) in frozen development progress. There have
been questions about it for many years, but nobody seems to be
interested enough to dive into it and fix the remaining problems.
Probably not many people use it.

> I did a little more research this afternoon, and it appears that the
> 0x8D 0x0A sequence is, in Clipper terms, a "soft carriage return", and
> perfectly normal in a MEMOEDIT field. Likewise, the 0x0D 0x0A sequence
> is a "hard carriage return". What is odd, of course, is that these
> characters are being displayed rather than causing an action.
>
> 0x0D Musical note
> 0x8D "Washing machine"
> 0x0A Lowercase i accent grave

Those two kinds of carriage returns should have been very obvious to the
developers who originally wrote the MemoEdit() code, so it is surprising
that they are visible. I only know MemoEdit() from casually reading the
code, so I don't know if this behavour is common. Maybe someone else
will jump in and comment. (Edit: See below)

> F2, F4, F5, and Insert behave as expected. F3 returns a ME_BOTTOMRIGHT
> code to MEMOEDIT(), which surprisingly /exits/ MEMOEDIT rather than
> moving the cursor. Further, Ctrl-B, which the MEMOEDIT documentation
> implies should re-format the current paragraph (and possibly relocate a
> number of "soft CRs", simply advances the cursor to the beginning of the
> next word, like Ctrl-F/Ctrl-RightArrow.

Unless someone suddenly feels an urge to work on the remaining problems
in MemoEdit() I can only suggest that you subclass it and do what you
need to do in the subclass. Like modifying the ME_BOTTOMRIGHT behavour,
for example.

One incompatibility, or incompleteness, that I know about is this one
from src\rtl\teditor.prg:

CASE nKey == K_CTRL_B
/* TODO: Resolve keycode collision with K_CTRL_RIGHT */
/* TODO: Implement reform paragraph */

CASE nKey == K_CTRL_T
/* TODO: Implement delete word right */

That is why Ctrl-B does not work. xHarbour has those keys implemeted, so
maybe it would be possible to borrow them from there.

Looking at the code for the HBEditor class again I found this comment
that I had not seen before:

/* TODO: add missing support for soft-newlines: hb_BChar( 141 ) +
hb_BChar( 10 ) */

And xHarbour has this comment:
// If memofield was created with Clipper, it needs to have chr( 141 )
+chr( 10 ) stripped

I think we are getting closer ...

> What I can't figure out for the life of me is what would make MEMOEDIT
> decide to display what would normally be considered control characters.
>
> Hm. The contents of the MEMO fields were originally created by the
> 16-bit DOS/Clipper app whose decompiled (and thus uncomented) source I
> have been working with. How, exactly, does the Harbour implementation of
> MEMOEDIT() decide whether a given byte represents a displayable
> character or is a control character?
>
> I suddenly realize that I've never checked to see how Clipper/Harbour
> handle CODEPAGEs and such, though it's far from clear why that would
> affect the MEMOEDIT editing keys. In any case, it sounds like a good
> place to start doing research... tomorrow. <grin!>

I know more about codepages than I know about MemoEdit() :-)

What is your codepage (or what should it be)? Judging from your name,
your way with words and your email domain I am guessing it is plain
"EN". And that is the default in Harbour. So if it is, it should not be
a factor.

If your codepage is not "EN", then we can talk about that.

What if you pass a string with "normal" content to MemoEdit(), save it
in a memo field and then read it back? Does that make any difference
compared to the already existing memos in the .fpt file? The soft CRs
seem to have their explanation, but you mentioned the hard CRs too, right?

Regards,
Klas

F McKenney

unread,
May 14, 2014, 2:44:28 PM5/14/14
to harbou...@googlegroups.com

Hi, Klas.

Aha! I had looked at the code in 'memoedit.prg', but didn't look any higher in the class hierarchy. Your quoted comments from HBEditor pretty well explain what I'm seeing.

I wrote this little throwaway which exhibits the problem:

#include "common.ch"
#include "memoedit.ch"
#include "inkey.ch"

hard_cr := chr(13) + chr(10)
soft_cr := chr(141) + chr(10)
m1 := "Now is the winter of" + soft_cr + "our discontent" ;
      + hard_cr + "made an eternal quote"
m2 := e"Now is the winter of\x8D\x0Aour discontent\x0D\x0Amade an eternal quote"
m_f := MEMOEDIT(m1,0,0,10,30)
? e"\n\n\n**********\n" + m_f + e"\n***************\n\n"

This is good, as it means I don't have to dig down into six or seven levels of (uncommented decompiled) code. This is not so good, as it means I'll have to add the functionality or something like it.

The specific keystrokes aren't so critical, but it has to be possible to insert something (hard CRs) into the MEMO fields which will force a newline in output in another section of code that creates reports.
 
> Hm. The contents of the MEMO fields were originally created by the
> 16-bit DOS/Clipper app whose decompiled (and thus uncomented) source I
> have been working with. How, exactly, does the Harbour implementation of
> MEMOEDIT() decide whether a given byte represents a displayable
> character or is a control character?
>
> I suddenly realize that I've never checked to see how Clipper/Harbour
> handle CODEPAGEs and such, though it's far from clear why that would
> affect the MEMOEDIT editing keys. In any case, it sounds like a good
> place to start doing research... tomorrow. <grin!>

I know more about codepages than I know about MemoEdit() :-)

What is your codepage (or what should it be)? Judging from your name,
your way with words and your email domain I am guessing it is plain
"EN". And that is the default in Harbour. So if it is, it should not be
a factor.

Definitely EN.


What if you pass a string with "normal" content to MemoEdit(), save it
in a memo field and then read it back? Does that make any difference
compared to the already existing memos in the .fpt file? The soft CRs
seem to have their explanation, but you mentioned the hard CRs too, right?

See above. Oh, and this is in Windows 8. (Sigh.)

The problem appears (at this point) to be that under Win8, at least, Harbour's MEMOEDIT() function considers \x8D\x0A a printable sequence (lowercase-I-accent-grave, washing-machine) rather than a control sequence but does recognize \x0D\x0A as a control sequence. Under Ubuntu 10.04 LTS, the \x0A is a control character but \x0D displays as a musical note and \x8D displays as lowercase-I-accent-grave.

This is, at its heart, an old, old edit-text-larger-than-screen-space problem: How do you provide a "window" on the text being edited in a way that "feels" natural but also makes "true" paragraph breaks visible. I need to think about this some more.

But first I think I'll go for a walk through the nearby park to clear my head. Maybe the turtles will have some advice. <grin!>


Frank

Klas Engwall

unread,
May 14, 2014, 6:31:04 PM5/14/14
to harbou...@googlegroups.com
Hi Frank,

> Aha! I had looked at the code in 'memoedit.prg', but didn't look any
> higher in the class hierarchy. Your quoted comments from HBEditor pretty
> well explain what I'm seeing.
>
> I wrote this little throwaway which exhibits the problem:

[snip code]

> This is good, as it means I don't have to dig down into six or seven
> levels of (uncommented decompiled) code. This is not so good, as it
> means I'll have to add the functionality or something like it.
>
> The specific keystrokes aren't so critical, but it has to be possible to
> insert something (hard CRs) into the MEMO fields which will force a
> newline in output in another section of code that creates reports.

I tested your sample and inserted a lot of "asdf asdf asdf" after
deleting the soft_cr "decoration", and it reflowed nicely. The hard_cr
worked too after hitting an extra Enter to create an empty line. Maybe
that is the way it was supposed to work from the beginning? Not just one
hard_cr in the middle of text but the paragraphs distinctly separated by
pressing Enter twice. But I never used MemoEdit() in Clipper other than
for testing ...

After Ctrl-W-ing out of MemoEdit() I had two separate paragraphs output
on screen filling the entire console window width with (of course) no
internal line breaks in the paragraphs.

I think this could most easily be solved by inserting the soft_crs after
exiting the editor but before saving to file:
1. How wide is the window? Answer: 30 characters
2. Where is the last space character within the first 30 characters?
Answer: Position 28, for example
3. Move the first 28 characters, including that space, to a new string
and add the soft_cr
4. Ltrim() the remaining original string in case there are double spaces
5. Loop to 2 while there are still characters left in the paragraph
Do all this while keeping track of where the first hard_cr will be coming up

When entering an existing memo into MemoEdit, simply remove the soft_crs
and start editing.

Unless I am missing something obvious, I think it could be that simple.
So MemoEdit() might be easily fixed in that regard. There is no need to
have the soft_crs in the memo while editing. The flowing of the
paragraph text does not need them at all, and they show up as garbage on
screen in any case.

The tricky part (and if I remember my Clipper tests from a previous life
correctly it was the case there too) is to make sure that a single
hard_cr inserted with Enter will be interpreted as a hard_cr and not
part of a paragraph that MemoEdit() is allowed to reformat. And it
definitely is impossible to see, especially for lines that *almost* fill
the editor width.

Next, when reading the memo from file and printing it, you would have to
insert real hard_crs instead of the soft ones. What is your experience
from how Clipper manages to do that?

> The problem appears (at this point) to be that under Win8, at least,
> Harbour's MEMOEDIT() function considers \x8D\x0A a printable sequence
> (lowercase-I-accent-grave, washing-machine) rather than a control
> sequence but does recognize \x0D\x0A as a control sequence. Under Ubuntu
> 10.04 LTS, the \x0A is a control character but \x0D displays as a
> musical note and \x8D displays as lowercase-I-accent-grave.

Remember that MemoEdit() is/was a Clipper/DOS feature and that Linux
linebreaks are different from DOS/Windows. You probably have to decide
if you are going to have a CRLF or a LF-only format in the memo file and
then convert between the two formats as you switch between the Windows
and Linux versions of your application.

You can set the linebreak character(s) to use in the application (or in
certain places in it) with Set(_SET_EOL,cEolChar) but it has to be
investigated if MemoEdit() obeys the setting. I don't think it will
solve anything in this case.

> This is, at its heart, an old, old edit-text-larger-than-screen-space
> problem: How do you provide a "window" on the text being edited in a way
> that "feels" natural but also makes "true" paragraph breaks visible. I
> need to think about this some more.

I am not quite sure what you mean here. Are you talking about a frame
around the area MemoEdit() is set up to use? I added that with the
@...box command, and it looked nice and felt natural when the cursor
moved to the next line upon reaching the right border. "True" paragrahps
with a blank line inbetween are not a problem, I think, but lists like ...
-----------------
Trains
Boats
Planes
----------------
... may not always work the way the person typing them expects (it seems).

> But first I think I'll go for a walk through the nearby park to clear my
> head. Maybe the turtles will have some advice. <grin!>

Well, it can't hurt asking them as long as other people don't see you
doing it :-)

Regards,
Klas

Klas Engwall

unread,
May 14, 2014, 9:10:23 PM5/14/14
to harbou...@googlegroups.com
Hi again Frank,

Here is a preliminary stab I had at the soft CR problem along the lines
I suggested - except that I did not ltrim() the remaining string that
I mentioned in my step #4 since doing that would be against the Clipper
docs.

I have not tested my solution for Clipper compatibility, this is just an
attempt to add and remove soft CRs. If a text without soft CRs is
edited, it will be saved after editing with soft CRs inserted at
positions determined from the editor width passed to MyMemoEdit(). That
is how the soft CRs were added to the originally unwrapped lines of the
sample text.

All other issues in the editor class remain, and, as I said, I am not
even sure that this attempt is Clipper compatible. But maybe it is a
start, and maybe you could test it against some real memos ...

The test prg will read the sample text I attached, remove the soft CRs,
send the text to MyMemoEdit(), re-add the soft CRs when it is returned,
and save the memo in a new file. Have fun :-)

Regards,
Klas
memotest.zip

F McKenney

unread,
May 31, 2014, 9:13:30 AM5/31/14
to harbou...@googlegroups.com

Klas,

First, my apologies for taking so long to get back to you. I've been a bit under the weather, but things seem to be better now.


On Wednesday, May 14, 2014 9:10:23 PM UTC-4, Klas Engwall wrote:
Here is a preliminary stab I had at the soft CR problem along the lines
I suggested  -  except that I did not ltrim() the remaining string that
I mentioned in my step #4 since doing that would be against the Clipper
docs.

Thank you for this. I've worked -- a little -- in other object-oriented environments, but this was my first encounter with Clipper's. I know that late-edition Clipper had some object-like features, since I encountered a few in this code I'm working on, but I had o idea it was quite so extensive. Or is some of it extensions added by the Harbour Project?

All other issues in the editor class remain, and, as I said, I am not
even sure that this attempt is Clipper compatible. But maybe it is a
start, and maybe you could test it against some real memos ...

I did, and it seemed to do the job. However -- and thanks in no small part to what I learned working my way through your code -- I finally realized that I was overlooking something: for this application, at least, nobody needs those soft CRs. I do have to deal with those which already exist in the legacy-but-still-in-use MEMO fields, but MEMOEDIT seems to re-wrap the MEMO field text each time it is invoked, and all the customer needs is the ability to insert and delete "real" EOLs, ones which will someday reach a printer or the screen in a report. My current solution involves:

  • Stripping (old) soft CRs from a MEMO field before MEMOEDIT sees them,
  • Letting MEMOEDIT (re-)wrap the MEMO field text within its window, and
  • Stripping out any new soft CRs added by MEMOEDIT when it exits.
This line of code (fortunately, the only call to MEMOEDIT):


    crv:= memoedit(fld, wm[2], wm[3], wm[4], wm[5], lwrite, "mefn")

is now three:

    crvi = MemoFixSoftCRs(fld)
    crv:= memoedit(crvi, wm[2], wm[3], wm[4], wm[5], lwrite, "mefn")
    crv := MemoFixSoftCRs(crv)

plus a subroutine:

// Harbour: Replace all soft CRs with spaces while preserving visual appearance
 
function MemoFixSoftCRs(mfstr)
 
  local s1
 
  soft_cr := e"\x8D\x0A"  // Windows/DOS chr(141) + chr(10)
 
  s1 :=  StrTran( mfstr, " "+ soft_cr, " ")
  s1 :=  StrTran( s1, soft_cr + " ", " ")
  s1 :=  StrTran( s1, soft_cr, " ")
 
return s1


It's not beautiful, and it's probably not the most efficient way to do the job, but it seems to work.

Oh, and in the process of checking my results I wound up writing this function because I coudn't find anything simpler:

function DumpHex(instr)

  local slen := len(instr)
  local c, i, j, lstr, rstr, ri
  local nc := 16                            // Columns
  local nr := int( ( slen + nc - 1 )/ nc )  // Rows or part
  local xstr := ""
  local pchars := "abcdefghijklmnopqrstuvwxyz" + ;
                  "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + ;
                  "0123456789" + "!@#$%^&*()_+-=" + ;
                  "{}|[]\:;<>?,./" + ;
                  e"\x22\x27" //  Quotes are always a problem

  ri := 0  // Running index
  for i := 1 to nr
    lstr := ""
    rstr := ""
    for j := 1 to nc
      ri := ri + 1
      if ri > slen    // If past end of input, fill row with blanks
        lstr := lstr + "   "
        rstr := rstr + " "
      else            // Sles process byte
        c := substr(instr, ri, 1)
        lstr := lstr + " " + ntoc( asc(c), 16, 2, "0" )
        if ( at(c,pchars) > 0 )
          rstr := rstr + c      // show character or ...
        else
          rstr := rstr + "."    // ... canonical non-printable
        endif
      endif
    next
    xstr := xstr + lstr + "   " + rstr + hard_cr
  next

return xstr


Again, there's probably a simpler, cleaner, more efficient way to do this, but I couldn't find it in the time i had. ( If I had a nickel for every time i've said that... <grin!> )

  Have fun :-)

Aha! Thanks! I knew there was something I forgot to put on my ToDo List!

And thank you again for all your help.


Frank

P.S. Has anyone else noticed that it's almost half-past 2014 already?

Klas Engwall

unread,
May 31, 2014, 4:00:59 PM5/31/14
to harbou...@googlegroups.com
Hi Frank,

>> Here is a preliminary stab I had at the soft CR problem along the lines
>> I suggested - except that I did not ltrim() the remaining string that
>> I mentioned in my step #4 since doing that would be against the Clipper
>> docs.
>
> Thank you for this. I've worked -- a little -- in other object-oriented
> environments, but this was my first encounter with Clipper's.

Well, I didn't even get into that department yet. All I did was borrow
the existing MemoEdit() function, rename it MyMemoEdit() and add the two
functions to remove and add back the soft CRs. I did that from inside
MyMemoEdit() because then I already knew what the line length in the
output was supposed to be, so I could make the result Clipper compatible
again.

The object oriented stuff you saw was from the original MemoEdit. And
MyMemoEdit() instantiates the same HBMemoEditor class as the original
function does.

> I know
> that late-edition Clipper had /some/ object-like features, since I
> encountered a few in this code I'm working on, but I had o idea it was
> quite so extensive. Or is some of it extensions added by the Harbour
> Project?

Clipper, before 5.3, had the tBrowse class, the Get class and the Error
class. 5.3 added radiobuttons, scrollbars and a few other things as
classes. The application programmer could only use the classes that were
provided, period. In Harbour there are many other classes, mostly
outside the strictly Clipper compatible area. But what is more important
is that in Harbour you can subclass any existing class and add whatever
you want in the subclass ... and of course write your own classes from
scratch.

If you want to add the missing functionality in MemoEdit() (besides
removing and adding back soft CRs on your way into and out of MemoEdit()
), then what you should do is to subclass HBMemoEditor (which is itself
a subclass of HBEditor) or maybe skip HBMemoEditor and write a subclass
of HBEditor based on code borrowed from HBMemoEditor. To use the new
subclass you would have to change the line in MyMemoEdit() that says

oEd := HBMemoEditor():New( [etc]

into a call to your new subclass. That was the second reason that I
borrowed from MemoEdit() into a new function.

There are also ways to add new methods and data to existing classes, but
I am not sure this is a good idea with a parent class that someone might
modify in the Harbour source tree one day out of your control.

>> All other issues in the editor class remain, and, as I said, I am not
>> even sure that this attempt is Clipper compatible. But maybe it is a
>> start, and maybe you could test it against some real memos ...
>
> I did, and it seemed to do the job.

OK, but it seemed a little to easily fixed :-). As I said, my MemoEdit()
experience is very limited, so I don't know how those soft CRs are used
in Clipper, whether they are kept while editing or stripped and put back
like I did. The stripped memo certainly seemed to behave properly while
being edited. If it was this simple, why did the xHarbour folks make a
comment about stripping instead of actually doing it? Oh, well ...

> However -- and thanks in no small
> part to what I learned working my way through your code -- I finally
> realized that I was overlooking something: for /this/ application, at
> least, nobody /needs/ those soft CRs. I do have to deal with those which
> already exist in the legacy-but-still-in-use MEMO fields, but MEMOEDIT
> seems to re-wrap the MEMO field text each time it is invoked, and all
> the customer needs is the ability to insert and delete "real" EOLs, ones
> which will someday reach a printer or the screen in a report. My current
> solution involves:

Precisely what I was thinking.

> * Stripping (old) soft CRs from a MEMO field before MEMOEDIT sees them,
> * Letting MEMOEDIT (re-)wrap the MEMO field text within its window, and
> * Stripping out any new soft CRs added by MEMOEDIT when it exits.
>
> This line of code (fortunately, the only call to MEMOEDIT):
>
> crv:= memoedit(fld, wm[2], wm[3], wm[4], wm[5], lwrite, "mefn")
>
> is now three:
>
> crvi = MemoFixSoftCRs(fld)
> crv:= memoedit(crvi, wm[2], wm[3], wm[4], wm[5], lwrite, "mefn")
> crv := MemoFixSoftCRs(crv)

Or wrap your fixing function inside a modified copy of MemoEdit() like
in my example.

>> Have fun :-)
>
> Aha! Thanks! I knew there was something I forgot to put on my ToDo List!

:-)

> And thank you again for all your help.

You're welcome

> P.S. Has anyone else noticed that it's almost half-past 2014 already?

Yes, we are not getting any younger :-)

Regards,
Klas
Reply all
Reply to author
Forward
0 new messages