Textmerge is a combination of several of FoxPro's best features—it creates low-level file output, performs runtime evaluation and eases formatting of different types of data. \ and \ are the textmerge equivalents of ? and ??, outputting to the destination specified by SET TEXTMERGE TO, rather than SET DEVICE TO. Starting in VFP 7, you have several new options for creating textmerge output, including the ability to send the results to a variable.
SET TEXTMERGE [ ON | OFF ] |
[ TO FileName | TO MEMVAR VarName [ ADDITIVE ] ]
[ WINDOW WindowName ]
[ SHOW | NOSHOW ]
cOnOrOff = SET( "TEXTMERGE" )
cMergeFile = SET( "TEXTMERGE", 2)
cShowOrNot = SET( "TEXTMERGE", 3)
nRecursionLevel = SET( "TEXTMERGE", 4)Here's the deal. When you issue the command SET TEXTMERGE TO FileName, a low-level file channel is opened and the file FileName is opened or created. The low-level file handle is stored in the system memory variable _TEXT. When you use the TO MEMVAR clause (added in VFP 7), there's no file involved, but the named variable is created, if necessary. Output created with the single or double backslash (\ or \) is echoed to the file or stored in the variable, with \ issuing a carriage return before outputting the remainder of the line, and \ issuing its characters immediately following the text that had been output before. "Big deal," you say. "I can do the same thing with SET ALTERNATE or SET PRINTER." Yes, BUT! Textmerge really shines when TEXTMERGE is set ON.
SET TEXTMERGE ON tells FoxPro to examine each line of output for expressions encased in textmerge delimiters. If these are found, the expression within delimiters is evaluated, and the result of that expression is output. Still not impressed? Here's the key: The result of the expressions is converted to text automatically—dates, numerics, datetimes, whatever. To output a line containing a number, date, datetime and page number, you would have to convert each one, as in:
? LTRIM(STR(nNumber,4)) + space(6) + ;
DTOC(Date()) + SPACE(7) + ;
TTOC(DateTime()) + SPACE(4) + ;
"Page #" + ltrim(_PAGENO)In a textmerge document, you would just say:
\<<nNumber>> <<Date()>> <<Datetime()>> Page # <<_PAGENO>>Now which would you prefer to have to decode and maintain six months after you wrote it?
And textmerge is fast! Ted wrote some processing code a while back to read through 800 HTML documents, parse the contents, and generate an HTML Help index in SiteMap format. Processing all of the files took eight seconds! One key factor was to set NOSHOW. With the text scrolling past on the screen, it took eight minutes for the same process.
|
The original release of VFP 7 sometimes crashes when you mix TEXT TO processing with SET TEXTMERGE processing. It's fixed in SP1. |
The remaining optional clauses are pretty straightforward. ADDITIVE specifies that output is appended to the end of an existing file or variable. WINDOW WindowName allows you to specify an output window where the echoed textmerge text should appear. We recommend you always specify a window if you want the output echoed, for two reasons. First, in Visual FoxPro 5 and later, it's possible to release the main FoxPro window and run your application as a top-level form. In that case, your output might be lost. Secondly, it's been our experience that Windows seems to slow down when outputting scrolling text to the screen or a window not on top. If you create a specific window for your textmerge, you can force it to be WONTOP() for the operation.
SHOW | NOSHOW specifies whether text output to the merge file should also be echoed to the screen or optional window.
If you choose to send output to a file, rather than using SET TEXTMERGE TO a particular file, we suggest you use FCREATE() or FOPEN() to access the file. Why? If SAFETY is ON, SET TEXTMERGE generates a confirmation dialog to overwrite the file. Any number of errors can prevent the file from being created—improper file names, bad drive designator, lack of rights—but FCREATE() and FOPEN() allow you to handle the errors using the simpler low-level error handler FERROR(), rather than the massive CASE statement needed to process all of FoxPro's possible file errors, or dropping though to your global error handler. If the low-level function was successful, you can set _TEXT to the file handle returned from these Low-level File Functions.
Overall, though, we recommend sending textmerge output to a string, then if a file is needed, using StrToFile().
There are other neat commands to use with text merging. TEXT...ENDTEXT allows you to include a block of text right in your program; it obeys the settings of _PRETEXT and evaluates any expressions within delimiters. It's also been enhanced in VFP 7 to include a lot of its settings right in the command.
The various forms of SET("TEXTMERGE") let you see how you have things set up. Some of them work better than others and some of them make more sense than others.
SET("TEXTMERGE"), by itself, returns either "ON" or "OFF". SET("TEXTMERGE",2) gives you the name of the file to which you've SET TEXTMERGE. SET("TEXTMERGE",3) tells you whether textmerge is currently SHOW or NOSHOW. Since textmerge can be recursive (when the string merged in contains the textmerge delimiters), SET("TEXTMERGE", 4) tells you how many levels of recursion are pending at the moment.
|
There's no way to find out what variable you've SET TEXTMERGE to. |
* The *best* examples of textmerge are available in your main
* Visual FoxPro directory - check out GENMENU.PRG and others.
* But here's something for you to try:
LOCAL lcOldPreText
* SET TEXTMERGE ON TO textmerg.txt NOSHOW && Don't do this!
SET TEXTMERGE TO textmerg.txt
SET TEXTMERGE ON NOSHOW
\Generated at <<DATE()>> <<TIME()>>
\
TEXT
This is a block of text with
no comments or anything before
it
ENDTEXT
\
\Now we add a pretext
\
lcOldPreText = _PRETEXT
_PRETEXT = "*"+CHR(09)
TEXT
Four score and seven years ago,
our forefathers (and mothers) brought
forth upon this continent a new nation,
ENDTEXT
_PRETEXT = lcOldPreText
\
\ And delimiters are evaluated within TEXT...ENDTEXT
\
TEXT
Today is <<DATE()>> and the time is <<TIME()>>
ENDTEXT
SET TEXTMERGE OFF
SET TEXTMERGE TO
MODI FILE textmerg.txt
* Textmerge to a variable
SET TEXTMERGE TO MEMVAR cHTML
SET TEXTMERGE ON NOSHOW
\<HTML>
\<HEAD>
\<TITLE><<Customer.Company>></TITLE>
\</HEAD>
\<BODY>
\Address: <<Customer.Address>>
\</BODY>
\</HTML>
* and so forth to build an HTML document
SET TEXTMERGE OFF
SET TEXTMERGE TO
StrToFile( cHTML, "MyHTMLDoc.HTM" )_PRETEXT = cTextToPrecede
cTextToPrecede = _PRETEXT
_TEXT = nHandle
nHandle = _TEXT_PRETEXT is not a system-generated excuse like "I just happened to be in the neighborhood," but a system memory variable that holds a character expression. This expression is inserted at the beginning of each line of text generated by the textmerge commands. Set _PRETEXT to "*" to comment a block of code, or to a set of tabs to indent a block.
_TEXT is a built-in FoxPro system memory variable. It contains the low-level file handle of the destination of textmerged output. Set _TEXT to –1 (negative one) to temporarily shut off output to the designated file. Since _TEXT stores the number of a low-level file handle opened for output, switching _TEXT programmatically allows you to switch output back and forth between several destinations, a trick the FoxPro 2.x screen generator used to separate startup and cleanup code.
_TEXT is set to –1 when you SET TEXTMERGE TO a variable. More importantly, the current textmerge output file is closed at that time, so you can't save the value of _TEXT and restore it after sending textmerge output to a variable.
_PRETEXT = "*" + CHR(9) && Comment and indent merged text.
SET TEXTMERGE TO D:\TEXTMERG.TXT
? _TEXT && Displays the opened file handle.SET TEXTMERGE DELIMITERS TO [ cLeftExp [, cRightExp ] ]
cAllDelimiters = SET( "TEXTMERGE", 1 )Delimiters specified with this command tell FoxPro what to look for when outputting a line with the textmerge commands , \, TEXT or TEXTMERGE(). Expressions contained within the delimiters are evaluated when TEXTMERGE is SET ON. If no delimiters are specified, they default to << and >>, respectively. If a single character expression is specified, it's used for both the left and right delimiters. Avoid using those single characters already used by other FoxPro functions—%, &, $, *, (, or ). Colons, used singly or doubly, are probably a safe bet, as long as you don't use the scope resolution operator in the code. It's best to leave the delimiters as is, unless you need to output the << or >> characters themselves. Each delimiter expression can be either one or two characters in length.
SET TEXTMERGE DELIMITERS TO "::", "::"
SET TEXTMERGE DELIMITERS TO "@~","@"
? SET("TEXTMERGE",1) && returns "@~@" - but which is which?cMergedOutput = TEXTMERGE( cString [, lRecursive
[, cLeftDelim [, cRightDelim ] ] ] )|
Parameter |
Value |
Meaning |
|
cString |
Character |
The string to be evaluated. |
|
lRecursive |
.T. |
If a merged expression contains the textmerge delimiters, keep evaluating the contents of the delimiters again until no more delimiters are found. |
|
.F. or omitted |
Evaluate strings inside the textmerge delimiters only once. |
|
|
cLeftDelim |
One or two characters |
The left delimiter for textmerge within the function. |
|
Omitted |
Use the current left delimiter from the SET TEXTMERGE DELIMITERS setting. |
|
|
cRightDelim |
One or two characters |
The right delimiter for textmerge within the function. |
|
Omitted |
Use the current right delimiter from the SET TEXTMERGE DELIMITERS setting. |
This function, added in VFP 7, makes textmerge easier than ever. No need to issue SET commands; no need to put text inside a TEXT ... ENDTEXT block. Just build the string and call the function.
If you don't specify delimiters in the function call, the current textmerge delimiters are used. However, specifying delimiters in the call doesn't change the current delimiters. Unlike SET TEXTMERGE DELIMITERS, with TEXTMERGE(), you can specify a left delimiter without specifying a right delimiter. In that case, the left delimiter in the function call is used, along with the current right delimiter.
#DEFINE CRLF CHR(13) + CHR(10)
cString = "<HTML>" + CRLF
cString = cString + "<HEAD>" + CRLF
cString = cString + "<TITLE><<Customer.Company>>" + ;
"</TITLE>" + CRLF
cString = cString + "<BODY>" + CRLF
cString = cString + "Address: <<Customer.Address>>" + CRLF
cString = cString + "</BODY>" + CRLF
cString = cString + "</HEAD>" + CRLF
cString = cString + "</HTML>"
cHTML = TextMerge( cString )FError(), Low-Level File Functions, Set Alternate, Set Printer, Text ... EndText


