Logo

Hacker’s Guide to Visual FoxPro
An irreverent look at how Visual FoxPro really works. Tells you the inside scoop on every command, function, property, event and method of Visual FoxPro.

MEMLINES(), MLINE(), _MLine

The functions MEMLINES() and MLINE() and the system variable _MLINE let you pull apart a memo field or multi-line character string into its component lines. MEMLINES() tells you how many lines the field contains while MLINE() returns a specified line. _MLINE keeps track of how far into the field you’ve gone looking for lines.

Usage

nNumberOfLines = MEMLINES(cString )
cResult = MLINE(cString, nLine [ , nStartPos ] )
_MLINE = nStartPos
nStartPos = _MLINE

Parameter

Value

Meaning

cString

Memo or Character

The string to be broken into lines.

nLine

Numeric

The line to return with MLINE().

nStartPos

Numeric

The offset from the beginning of the string to start looking for lines.

nNumberOfLines

Numeric

The number of lines in cString (based on SET("MEMOWIDTH")).

cResult

Character

The nLine-th line of cString, starting from nStartPos, based on SET("MEMOWIDTH"). This string is trimmed and doesn't include a carriage return or line feed at the end.

Both MEMLINES() and MLINE() base their results on the current setting of MEMOWIDTH. In addition, they both divide the string at a space, if possible. If the string doesn’t have any spaces within SET(“MEMOWIDTH”) characters, the line ends after exactly that number. If the string contains any carriage-return characters (CHR(13)), those also indicate line breaks no matter how many characters precede them. (Note that the line feed character, CHR(10), does not count as a line break for these functions.)

_MLINE lets you return successive lines without having to count as you go. Each call to MLINE() assigns _MLINE the place to start looking for the next line after the one returned. That is, if MLINE() returns a 23-character line from the beginning of a string, _MLINE gets set to 24 automatically. This means you can pass _MLINE for nStartPos and leave nLine set at 1 to return successive lines of a memo field or string. To do so, set _MLINE=0 before applying MLINE() the first time.

Using _MLINE to retrieve a series of lines has a spectacular effect on the speed in processing large strings. In the first code snippet, we try to read a string one line at a time by incrementing the line number:

FOR I = 1 TO MEMLINES()
  ? MLINE(myString,i)
NEXT

This second snippet doesn’t appear much different:

_MLINE = 0
FOR I = 1 TO MEMLINES()
  ? MLINE(myString,1,_MLINE)
NEXT

However, the second code fragment can run circles around the first! Why? The reason is that, in the first example, Visual FoxPro has to read the file and break it into lines, one line at a time, until it gets to the line number you’ve specified. In the second example, you’ve already supplied the offset where the function must start counting, and told it just to return the first line—isn’t that a lot easier?

One subtlety here is that _MLINE is an offset, not a position. That is, it’s the number of characters to move from the first character to find the starting position. Huh? With an offset, you start at a given position and move the specified number of characters to the right. The one you land on is the place to start. This means that _MLINE is one less than the position of the first character to be considered.

If you think of _MLINE as a position, you’ll run into trouble in one situation. The interaction between MLINE() and _MLINE is designed to remove the blank space between words when a line break occurs. That is, the space between two words doesn’t become part of either line when that word break is used as a line break. So, _MLINE appears to point at the space.

However, if there are no spaces and MLINE() simply takes the maximum number of characters, _MLINE points at the last character in the first line. The second line properly starts with the next character. What all this means is that you can’t count on _MLINE being the number of characters used so far.

Many folks miss the fact that this group of goodies can be applied to character strings just as well as to memo fields. They’re very handy for dividing a message to be displayed into lines of the right length.

The ALINES() function added in VFP 6 lets you do a lot of the same things you can do with MLINE() and _MLINE, but doesn’t trim the result or rely on the setting of MEMOWIDTH, which may have advantages for many uses. ALINES() is generally far faster than MLINE(), so use it unless you need MEMOWIDTH respected.

These functions should also be considered as replacements for low-level functions on text files. Low-level functions typically read a file one character or line at a time, process it, and then go back for more. If, instead of doing this, you plunk the whole file into a memory variable or memo field, you can then run these functions on the result. Because Visual FoxPro will buffer as much of the data in memory as it can manage, the difference in performance can be impressive.

Example

* Take a message and divide it into appropriate length lines
nOldMemo = SET( "MEMOWIDTH" )
SET MEMOWIDTH TO 30

nNumLines = MEMLINES( cMessage )
DIMENSION aMessage[ nNumLines ]

_MLINE = 0
FOR nCnt = 1 TO nNumLines
    aMessage[nCnt] = MLINE(cMessage, 1, _MLINE)
ENDFOR

SET MEMOWIDTH TO nOldMemo

See Also

ALines(), AtCLine(), AtLine(), Low-Level File Functions, RAtLine(), Set MemoWidth