home *** CD-ROM | disk | FTP | other *** search
- /***
- * Frmrun.prg
- * Clipper 5.0 REPORT FORM runtime system
- * Copyright (c) 1990 Nantucket Corp. All rights reserved.
- *
- * Compile: /n/w/m
- */
-
-
- #include "frmdef.ch"
- #include "error.ch"
-
- STATIC aReportData, nPageNumber, nLinesLeft, aReportTotals
- STATIC aGroupTotals, lFirstPass, lFormFeeds, nMaxLinesAvail
-
- FUNCTION __ReportForm( cFRMName, lPrinter, cAltFile, lNoConsole, bFor, ;
- bWhile, nNext, nRecord, lRest, lPlain, cHeading, ;
- lBEject, lSummary )
-
- LOCAL lPrintOn, lConsoleOn // Status of PRINTER and CONSOLE
- LOCAL cExtraFile, lExtraState // Status of EXTRA
- LOCAL nCol, nGroup
- LOCAL xBreakVal, lBroke := .F.
- LOCAL err
-
- LOCAL lAnyTotals
- LOCAL lAnySubTotals
-
- // Resolve parameters
- IF cFRMName == NIL
- err := ErrorNew()
- err:severity := 2
- err:genCode := EG_ARG
- err:subSystem := "FRMLBL"
- Eval(ErrorBlock(), err)
- ELSE
- IF AT( ".", cFRMName ) == 0
- cFRMName := TRIM( cFRMName ) + ".FRM"
- ENDIF
- ENDIF
-
- IF lPrinter == NIL
- lPrinter := .F.
- ENDIF
-
- IF cHeading == NIL
- cHeading := ""
- ENDIF
-
- // Set output devices
- lPrintOn := SET( _SET_PRINTER, lPrinter )
-
- IF lNoConsole
- lConsoleOn := SET( _SET_CONSOLE, .F. )
- ENDIF
-
- IF lPrinter // To the printer
- lFormFeeds := .T.
- ELSE
- lFormFeeds := .F.
- ENDIF
-
- IF (!Empty(cAltFile)) // To file
- cExtraFile := SET( _SET_EXTRAFILE, cAltFile )
- lExtraState := SET( _SET_EXTRA, .T. )
- ENDIF
-
-
- BEGIN SEQUENCE
-
- aReportData := __FrmLoad( cFRMName ) // Load the frm into an array
- nMaxLinesAvail := aReportData[RP_LINES]
-
- // Modify aReportData based on the report parameters
- IF lSummary != NIL // Set the summary only flag
- aReportData[ RP_SUMMARY ] := lSummary
- ENDIF
- IF lBEject != NIL
- aReportData[ RP_BEJECT ] := .F.
- ENDIF
- IF lPlain // Set plain report flag
- aReportData[ RP_PLAIN ] := .T.
- cHeading := ""
- lFormFeeds := .F.
- ENDIF
- aReportData[ RP_HEADING ] := cHeading
-
- // Add to the left margin if a SET MARGIN has been defined
- // NOTE: uncommenting this line will cause REPORT FORM to respect
- // SET MARGIN to screen/to file, but double the margin TO PRINT
- // aReportData[ RP_LMARGIN ] += SET( _SET_MARGIN )
-
- nPageNumber := 1 // Set the initial page number
- lFirstPass := .T. // Set the first pass flag
-
- nLinesLeft := aReportData[ RP_LINES ]
-
- // Check to see if a "before report" eject, or TO FILE has been specified
- IF aReportData[ RP_BEJECT ]
- EjectPage()
- ENDIF
-
- // Generate the initial report header manually (in case there are no
- // records that match the report scope)
- ReportHeader()
-
- // Initialize aReportTotals to track both group and report totals, then
- // set the column total elements to 0 if they are to be totaled, otherwise
- // leave them NIL
- aReportTotals := ARRAY( LEN(aReportData[RP_GROUPS]) + 1, ;
- LEN(aReportData[RP_COLUMNS]) )
-
- // Column total elements
- FOR nCol := 1 TO LEN(aReportData[RP_COLUMNS])
- IF aReportData[RP_COLUMNS,nCol,RC_TOTAL]
- FOR nGroup := 1 TO LEN(aReportTotals)
- aReportTotals[nGroup,nCol] := 0
- NEXT
- ENDIF
- NEXT
-
- // Initialize aGroupTotals as an array
- aGroupTotals := ARRAY( LEN(aReportData[RP_GROUPS]) )
-
- // Execute the actual report based on matching records
- DBEval( { || ExecuteReport() }, bFor, bWhile, nNext, nRecord, lRest )
-
- // Generate any totals that may have been identified
- // Make a pass through all the groups
- FOR nGroup := LEN(aReportData[RP_GROUPS]) TO 1 STEP -1
-
-
- // make sure group has subtotals
- lAnySubTotals := .F.
- FOR nCol := 1 TO LEN(aReportData[RP_COLUMNS])
- IF aReportData[RP_COLUMNS,nCol,RC_TOTAL]
- lAnySubTotals := .T.
- EXIT // NOTE
- ENDIF
- NEXT
-
- IF !lAnySubTotals
- LOOP // NOTE
- ENDIF
-
-
- // Check to see if we need to eject the page
- IF nLinesLeft < 2
- EjectPage()
- IF aReportData[ RP_PLAIN ]
- nLinesLeft := 1000
- ELSE
- ReportHeader()
- ENDIF
- ENDIF
-
- // Print the first line
- PrintIt( SPACE(aReportData[RP_LMARGIN]) + ;
- IF(nGroup==1,"** Subtotal **","* Subsubtotal *") )
-
- // Print the second line
- QQOUT( SPACE(aReportData[RP_LMARGIN]) )
- FOR nCol := 1 TO LEN(aReportData[RP_COLUMNS])
- IF nCol > 1
- QQOUT( " " )
- ENDIF
- IF aReportData[RP_COLUMNS,nCol,RC_TOTAL]
- QQOUT( TRANSFORM(aReportTotals[nGroup+1,nCol], ;
- aReportData[RP_COLUMNS,nCol,RC_PICT]) )
- ELSE
- QQOUT( SPACE(aReportData[RP_COLUMNS,nCol,RC_WIDTH]) )
- ENDIF
- NEXT
-
- // Send a cr/lf for the last line
- QOUT()
-
- NEXT
-
- // Generate the "Grand totals"
- // Check to see if we need to eject the page
- IF nLinesLeft < 2
- EjectPage()
- IF aReportData[ RP_PLAIN ]
- nLinesLeft := 1000
- ELSE
- ReportHeader()
- ENDIF
- ENDIF
-
-
- // Any report totals?
- lAnyTotals := .F.
- FOR nCol := 1 TO LEN(aReportData[RP_COLUMNS])
- IF aReportData[RP_COLUMNS,nCol,RC_TOTAL]
- lAnyTotals := .T.
- EXIT
- ENDIF
- NEXT
-
-
- IF lAnyTotals
-
- // Print the first line
- PrintIt( SPACE(aReportData[RP_LMARGIN]) + "*** Total ***" )
-
- // Print the second line
- QQOUT( SPACE(aReportData[RP_LMARGIN]) )
- FOR nCol := 1 TO LEN(aReportData[RP_COLUMNS])
- IF nCol > 1
- QQOUT( " " )
- ENDIF
- IF aReportData[RP_COLUMNS,nCol,RC_TOTAL]
- QQOUT( TRANSFORM(aReportTotals[1,nCol], ;
- aReportData[RP_COLUMNS,nCol,RC_PICT]) )
- ELSE
- QQOUT( SPACE(aReportData[RP_COLUMNS,nCol,RC_WIDTH]) )
- ENDIF
- NEXT
-
- // Send a cr/lf for the last line
- QOUT()
-
- END
-
-
- // Check to see if an "after report" eject, or TO FILE has been specified
- IF aReportData[ RP_AEJECT ]
- EjectPage()
- ENDIF
-
-
- RECOVER USING xBreakVal
-
- lBroke := .T.
-
- END // Sequence
-
-
- // Clean up and leave
- aReportData := NIL // Recover the space
- aReportTotals := NIL
- aGroupTotals := NIL
- nPageNumber := NIL
- lFirstPass := NIL
- nLinesLeft := NIL
- lFormFeeds := NIL
- nMaxLinesAvail := NIL
-
- // clean up
- SET( _SET_PRINTER, lPrintOn ) // Set the printer back to prior state
- SET( _SET_CONSOLE, lConsoleOn ) // Set the console back to prior state
-
- IF (!Empty(cAltFile)) // Set extrafile back
- SET( _SET_EXTRAFILE, cExtraFile )
- SET( _SET_EXTRA, lExtraState )
- ENDIF
-
- IF lBroke
- // keep the break value going
- BREAK xBreakVal
- END
-
- RETURN NIL
-
-
-
- /***
- * ExecuteReport() --> NIL
- * Executed by DBEVAL() for each record that matches record scope
- */
- STATIC FUNCTION ExecuteReport
- LOCAL aRecordHeader := {} // Header for the current record
- LOCAL aRecordToPrint := {} // Current record to print
- LOCAL nCol // Counter for the column work
- LOCAL nGroup // Counter for the group work
- LOCAL lGroupChanged := .F. // Has any group changed?
- LOCAL nMaxLines // Number of lines needed by record
- LOCAL nLine // Counter for each record line
- LOCAL cLine // Current line of text for parsing
- LOCAL nLastElement // Last element pointer if record is
-
- LOCAL lAnySubTotals
- // too large for a page
-
- // Add to the main column totals
- FOR nCol := 1 TO LEN(aReportData[RP_COLUMNS])
- IF aReportData[RP_COLUMNS,nCol,RC_TOTAL]
- // If this column should be totaled, do it
- aReportTotals[ 1 ,nCol] += ;
- EVAL( aReportData[RP_COLUMNS,nCol,RC_EXP] )
- ENDIF
- NEXT
-
- // Determine if any of the groups have changed. If so, add the appropriate
- // line to aRecordHeader for totaling out the previous records
- IF !lFirstPass // Don't bother first time through
-
- // Make a pass through all the groups
- FOR nGroup := LEN(aReportData[RP_GROUPS]) TO 1 STEP -1
-
-
- // make sure group has subtotals
- lAnySubTotals := .F.
- FOR nCol := 1 TO LEN(aReportData[RP_COLUMNS])
- IF aReportData[RP_COLUMNS,nCol,RC_TOTAL]
- lAnySubTotals := .T.
- EXIT // NOTE
- ENDIF
- NEXT
-
- IF !lAnySubTotals
- LOOP // NOTE
- ENDIF
-
-
-
- // If this group has changed since the last record
- IF MakeAStr(EVAL(aReportData[RP_GROUPS,nGroup,RG_EXP]),;
- aReportData[RP_GROUPS,nGroup,RG_TYPE]) != aGroupTotals[nGroup]
- AADD( aRecordHeader, IF(nGroup==1,"** Subtotal **","* Subsubtotal *") )
- AADD( aRecordHeader, "" )
-
- // Cycle through the columns, adding either the group
- // amount from aReportTotals or spaces wide enough for
- // the non-totaled columns
- FOR nCol := 1 TO LEN(aReportData[RP_COLUMNS])
- IF aReportData[RP_COLUMNS,nCol,RC_TOTAL]
- aRecordHeader[ LEN(aRecordHeader) ] += ;
- TRANSFORM(aReportTotals[nGroup+1,nCol], ;
- aReportData[RP_COLUMNS,nCol,RC_PICT])
- // Zero out the group totals column from aReportTotals
- aReportTotals[nGroup+1,nCol] := 0
- ELSE
- aRecordHeader[ LEN(aRecordHeader) ] += ;
- SPACE(aReportData[RP_COLUMNS,nCol,RC_WIDTH])
- ENDIF
- aRecordHeader[ LEN(aRecordHeader) ] += " "
- NEXT
- // Get rid of the extra space from the last column
- aRecordHeader[LEN(aRecordHeader)] := ;
- LEFT( aRecordHeader[LEN(aRecordHeader)], ;
- LEN(aRecordHeader[LEN(aRecordHeader)]) - 1 )
- ENDIF
- NEXT
-
- ENDIF
-
- lFirstPass = .F.
-
- // Add to aRecordHeader in the event that the group has changed and
- // new group headers need to be generated
-
- // Cycle through the groups
- FOR nGroup := 1 TO LEN(aReportData[RP_GROUPS])
- // If the group has changed
- IF MakeAStr(EVAL(aReportData[RP_GROUPS,nGroup,RG_EXP]),;
- aReportData[RP_GROUPS,nGroup,RG_TYPE]) == aGroupTotals[nGroup]
- ELSE
- AADD( aRecordHeader, "" ) // The blank line
- AADD( aRecordHeader, IF(nGroup==1,"** ","* ") +;
- aReportData[RP_GROUPS,nGroup,RG_HEADER] + " " +;
- MakeAStr(EVAL(aReportData[RP_GROUPS,nGroup,RG_EXP]), ;
- aReportData[RP_GROUPS,nGroup,RG_TYPE]) )
- ENDIF
- NEXT
-
- // Is there anything in the record header?
- IF LEN( aRecordHeader ) > 0
- // Determine if aRecordHeader will fit on the current page. If not,
- // start a new header
- IF LEN( aRecordHeader ) > nLinesLeft
- EjectPage()
- IF aReportData[ RP_PLAIN ]
- nLinesLeft := 1000
- ELSE
- ReportHeader()
- ENDIF
- ENDIF
-
- // Send aRecordHeader to the output device, resetting nLinesLeft
- AEVAL( aRecordHeader, ;
- { | HeaderLine | ;
- PrintIt( SPACE(aReportData[RP_LMARGIN])+ HeaderLine ) ;
- } ;
- )
- nLinesLeft -= LEN( aRecordHeader )
-
- // Make sure it didn't hit the bottom margin
- IF nLinesLeft == 0
- EjectPage()
- IF aReportData[ RP_PLAIN ]
- nLinesLeft := 1000
- ELSE
- ReportHeader()
- ENDIF
- ENDIF
- ENDIF
-
- // Add to the group totals
- FOR nCol := 1 TO LEN(aReportData[RP_COLUMNS])
- // If this column should be totaled, do it
- IF aReportData[RP_COLUMNS,nCol,RC_TOTAL]
- // Cycle through the groups
- FOR nGroup := 1 TO LEN( aReportTotals ) - 1
- aReportTotals[nGroup+1,nCol] += ;
- EVAL( aReportData[RP_COLUMNS,nCol,RC_EXP] )
- NEXT
- ENDIF
- NEXT
-
- // Reset the group expressions in aGroupTotals
- FOR nGroup := 1 TO LEN(aReportData[RP_GROUPS])
- aGroupTotals[nGroup] := MakeAStr(EVAL(aReportData[RP_GROUPS,nGroup,RG_EXP]),;
- aReportData[RP_GROUPS,nGroup,RG_TYPE])
- NEXT
-
- // Only run through the record detail if this is NOT a summary report
- IF !aReportData[ RP_SUMMARY ]
- // Determine the max number of lines needed by each expression
- nMaxLines := 1 // $BH 2/14/91
- FOR nCol := 1 TO LEN(aReportData[RP_COLUMNS])
- IF aReportData[RP_COLUMNS,nCol,RC_TYPE] $ "CM"
- nMaxLines := MAX(XMLCOUNT(EVAL(aReportData[RP_COLUMNS,nCol,RC_EXP]),;
- aReportData[RP_COLUMNS,nCol,RC_WIDTH]), nMaxLines)
- ENDIF
- NEXT
-
- // Size aRecordToPrint to the maximum number of lines it will need, then
- // fill it with nulls
- ASIZE( aRecordToPrint, nMaxLines )
- AFILL( aRecordToPrint, "" )
-
- // Load the current record into aRecordToPrint
- FOR nCol := 1 TO LEN(aReportData[RP_COLUMNS])
- FOR nLine := 1 TO nMaxLines
- // Check to see if it's a memo or character
- IF aReportData[RP_COLUMNS,nCol,RC_TYPE] $ "CM"
- // Load the current line of the current column into cLine
- cLine := XMEMOLINE(TRIM(EVAL(aReportData[RP_COLUMNS,nCol,RC_EXP])),;
- aReportData[RP_COLUMNS,nCol,RC_WIDTH], nLine )
- cLine := PADR( cLine, aReportData[RP_COLUMNS,nCol,RC_WIDTH] )
- ELSE
- IF nLine == 1
- cLine := TRANSFORM(EVAL(aReportData[RP_COLUMNS,nCol,RC_EXP]),;
- aReportData[RP_COLUMNS,nCol,RC_PICT])
- cLine := PADR( cLine, aReportData[RP_COLUMNS,nCol,RC_WIDTH] )
- ELSE
- cLine := SPACE( aReportData[RP_COLUMNS,nCol,RC_WIDTH])
- ENDIF
- ENDIF
- // Add it to the existing report line
- IF nCol > 1
- aRecordToPrint[ nLine ] += " "
- ENDIF
- aRecordToPrint[ nLine ] += cLine
- NEXT
- NEXT
-
- // Determine if aRecordToPrint will fit on the current page
- IF LEN( aRecordToPrint ) > nLinesLeft
- // The record will not fit on the current page - will it fit on
- // a full page? If not, break it up and print it.
- IF LEN( aRecordToPrint ) > nMaxLinesAvail
- // This record is HUGE! Break it up...
- nLine := 1
- DO WHILE nLine < LEN( aRecordToPrint )
- PrintIt( SPACE(aReportData[RP_LMARGIN]) + aRecordToPrint[nLine] )
- nLine++
- nLinesLeft--
- IF nLinesLeft == 0
- EjectPage()
- IF aReportData[ RP_PLAIN ]
- nLinesLeft := 1000
- ELSE
- ReportHeader()
- ENDIF
- ENDIF
- ENDDO
- ELSE
- EjectPage()
- IF aReportData[ RP_PLAIN ]
- nLinesLeft := 1000
- ELSE
- ReportHeader()
- ENDIF
- AEVAL( aRecordToPrint, ;
- { | RecordLine | ;
- PrintIt( SPACE(aReportData[RP_LMARGIN])+ RecordLine ) ;
- } ;
- )
- nLinesLeft -= LEN( aRecordToPrint )
- ENDIF
- ELSE
- // Send aRecordToPrint to the output device, resetting nLinesLeft
- AEVAL( aRecordToPrint, ;
- { | RecordLine | ;
- PrintIt( SPACE(aReportData[RP_LMARGIN])+ RecordLine ) ;
- } ;
- )
- nLinesLeft -= LEN( aRecordToPrint )
- ENDIF
-
- // Make sure it didn't hit the bottom margin
- IF nLinesLeft == 0
- EjectPage()
- IF aReportData[ RP_PLAIN ]
- nLinesLeft := 1000
- ELSE
- ReportHeader()
- ENDIF
- ENDIF
-
- // Tack on the spacing for double/triple/etc.
- IF aReportData[ RP_SPACING ] > 1
- IF nLinesLeft > aReportData[ RP_SPACING ] - 1
- FOR nLine := 2 TO aReportData[ RP_SPACING ]
- PrintIt()
- nLinesLeft--
- NEXT
- ENDIF
- ENDIF
-
- ENDIF // Was this a summary report?
-
- RETURN NIL
-
-
- STATIC FUNCTION ReportHeader
- LOCAL nLinesInHeader := 0
- LOCAL aPageHeader := {}
- LOCAL nHeadingLength := aReportData[RP_WIDTH] - aReportData[RP_LMARGIN] - 30
- LOCAL nCol, nLine, nMaxColLength, nGroup, cHeader
-
- // Create the header and drop it into aPageHeader
-
- // Start with the heading
- IF !aReportData[ RP_PLAIN ] // If not a plain paper report, build
- IF aReportData[RP_HEADING] == "" // the heading
- AADD( aPageHeader, "Page No." + STR(nPageNumber,6) )
- ELSE
- nLinesInHeader := XMLCOUNT( aReportData[RP_HEADING], nHeadingLength )
- FOR nLine := 1 TO nLinesInHeader
- AADD( aPageHeader, SPACE(15) + ;
- PADC(TRIM(XMEMOLINE(aReportData[RP_HEADING],nHeadingLength,nLine)),;
- nHeadingLength))
- NEXT
- aPageHeader[ 1 ] := STUFF( aPageHeader[ 1 ], 1, 14, ;
- "Page No." + STR(nPageNumber,6) )
- ENDIF
- AADD( aPageHeader, DTOC(DATE()) )
- ENDIF
-
- // Tack on the actual header from the FRM
- FOR nLine := 1 TO LEN( aReportData[RP_HEADER] )
- AADD( aPageHeader, ;
- SPACE( ( aReportData[RP_WIDTH] - aReportData[RP_LMARGIN] - ;
- aReportData[RP_RMARGIN] - ;
- Len( aReportData[RP_HEADER,nLine] ) ) / 2 ) + ;
- aReportData[RP_HEADER,nLine] )
- NEXT
-
- // S87 compat.
- AADD( aPageHeader, "" )
-
- // Now add the column headings
- nLinesInHeader := LEN( aPageHeader )
-
- // Determine the longest column header
- nMaxColLength := 0
- FOR nCol := 1 TO LEN( aReportData[ RP_COLUMNS ] )
- nMaxColLength := MAX( LEN(aReportData[RP_COLUMNS,nCol,RC_HEADER]), ;
- nMaxColLength )
- NEXT
- FOR nCol := 1 TO LEN( aReportData[ RP_COLUMNS ] )
- ASIZE( aReportData[RP_COLUMNS,nCol,RC_HEADER], nMaxColLength )
- NEXT
-
- FOR nLine := 1 TO nMaxColLength
- AADD( aPageHeader, "" )
- NEXT
-
- FOR nCol := 1 TO LEN(aReportData[RP_COLUMNS]) // Cycle through the columns
- FOR nLine := 1 TO nMaxColLength
- IF nCol > 1
- aPageHeader[ nLinesInHeader + nLine ] += " "
- ENDIF
- IF aReportData[RP_COLUMNS,nCol,RC_HEADER,nLine] == NIL
- aPageHeader[ nLinesInHeader + nLine ] += ;
- SPACE( aReportData[RP_COLUMNS,nCol,RC_WIDTH] )
- ELSE
- IF aReportData[RP_COLUMNS,nCol,RC_TYPE] == "N"
- aPageHeader[ nLinesInHeader + nLine ] += ;
- PADL(aReportData[RP_COLUMNS,nCol,RC_HEADER,nLine],;
- aReportData[RP_COLUMNS,nCol,RC_WIDTH])
- ELSE
- aPageHeader[ nLinesInHeader + nLine ] += ;
- PADR(aReportData[RP_COLUMNS,nCol,RC_HEADER,nLine],;
- aReportData[RP_COLUMNS,nCol,RC_WIDTH])
- ENDIF
- ENDIF
- NEXT
- NEXT
-
- // Insert the two blank lines between the heading and the actual data
- AADD( aPageHeader, "" )
- AADD( aPageHeader, "" )
-
- // Send it to the output device
- IF lFirstPass
- QOUT()
- ENDIF
-
- AEVAL( aPageHeader, ;
- { | HeaderLine | ;
- PrintIt( SPACE(aReportData[RP_LMARGIN])+ HeaderLine ) ;
- } ;
- )
-
- // Set the page number and number of available lines
- nPageNumber++
- nLinesLeft := aReportData[RP_LINES] - LEN( aPageHeader )
- nMaxLinesAvail := aReportData[RP_LINES] - LEN( aPageHeader )
-
- RETURN NIL
-
- /***
- * MakeStr( <exp>, <cType> ) --> value
- * Convert a value of any data type into string to add to the group header
- */
- STATIC FUNCTION MakeAStr( uVar, cType )
- LOCAL cString
- DO CASE
- CASE UPPER(cType) == "D"
- cString := DTOC( uVar )
-
- CASE UPPER(cType) == "L"
- cString := IF( uVar, "T", "F" )
-
- CASE UPPER(cType) == "N"
- cString := STR( uVar )
-
- CASE UPPER(cType) == "C"
- cString := uVar
-
- OTHERWISE
- cString := "INVALID EXPRESSION"
- ENDCASE
- RETURN( cString )
-
- /***
- * PrintIt( <cString> ) --> NIL
- * Print a string, THEN send a CRLF
- */
- STATIC FUNCTION PrintIt( cString )
-
- IF cString == NIL
- cString := ""
- ELSE
- // prevents output of trailing space, also prevents wrapping of some
- // lines when sent to screen or 80-column printer. Comment out this
- // line for complete Summer 87 compatibility.
- // cString := Trim( cString )
- ENDIF
-
- QQOUT( cString )
- QOUT()
-
- RETURN NIL
-
- /***
- * EjectPage() --> NIL
- * Eject a page if the form feed option is set
- */
- STATIC FUNCTION EjectPage
- IF lFormFeeds
- EJECT
- ENDIF
- RETURN NIL
-
-
- STATIC FUNCTION XMLCOUNT( cString, nLineLength, nTabSize, lWrap )
-
- // Set defaults if none specified
- nLineLength := IF( nLineLength == NIL, 79, nLineLength )
- nTabSize := IF( nTabSize == NIL, 4, nTabSize )
- lWrap := IF( lWrap == NIL, .T., .F. )
-
- IF nTabSize >= nLineLength
- nTabSize := nLineLength - 1
- ENDIF
-
- RETURN( MLCOUNT( TRIM(cString), nLineLength, nTabSize, lWrap ) )
-
-
- STATIC FUNCTION XMEMOLINE( cString, nLineLength, nLineNumber, nTabSize, lWrap )
-
- // Set defaults if none specified
- nLineLength := IF( nLineLength == NIL, 79, nLineLength )
- nLineNumber := IF( nLineNumber == NIL, 1, nLineNumber )
- nTabSize := IF( nTabSize == NIL, 4, nTabSize )
- lWrap := IF( lWrap == NIL, .T., lWrap )
-
- IF nTabSize >= nLineLength
- nTabSize := nLineLength - 1
- ENDIF
-
- RETURN( MEMOLINE( cString, nLineLength, nLineNumber, nTabSize, lWrap ) )
-
-