From 2f672ef210bad181d7f9226d66022019872f2a4d Mon Sep 17 00:00:00 2001 From: "Alexander S.Kresin" Date: Mon, 25 May 2009 06:36:08 +0000 Subject: [PATCH] 2009-05-25 10:30 UTC+0300 Alexander Kresin --- harbour/ChangeLog | 18 + harbour/utils/Makefile | 1 + harbour/utils/hbformat/Makefile | 37 + harbour/utils/hbformat/hbformat.ini | 90 +++ harbour/utils/hbformat/hbformat.prg | 1048 +++++++++++++++++++++++++++ 5 files changed, 1194 insertions(+) create mode 100644 harbour/utils/hbformat/Makefile create mode 100644 harbour/utils/hbformat/hbformat.ini create mode 100644 harbour/utils/hbformat/hbformat.prg diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 72a15020c1..3569ebe433 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,24 @@ past entries belonging to these authors: Viktor Szakats. */ +2009-05-25 10:30 UTC+0300 Alexander Kresin + + utils/hbformat + + utils/hbformat/hbformat.prg + + utils/hbformat/hbformat.ini + + utils/hbformat/Makefile + + Harbour source formatter utility has been added. The command line to call it: + hbformat [-r] [options] [@config.ini] file[s] + + -r option ( recursive ) forces formatting files in all nested directories. + Default options ( their values you may find commented in a provided hbformat.ini ) + provides the style, accepted in Harbour prgs. The hbformat.ini must be in the same + directory, where the hbformat.exe is. You can use additional ini file and point to + it in a command line with the '@' before it. Options in a command line are the same, + which are in ini file - for example, -lCase=no forces to not make case conversion. + + * utils/Makefile + * Makefile has been changed to build the hbformat + 2009-05-24 13:44 UTC+0200 Viktor Szakats (harbour.01 syenar hu) * INSTALL * Minor cleanups. diff --git a/harbour/utils/Makefile b/harbour/utils/Makefile index 28e0309735..229cae7fe7 100644 --- a/harbour/utils/Makefile +++ b/harbour/utils/Makefile @@ -9,6 +9,7 @@ DIRS=\ hbmk2 \ hbi18n \ hbtest \ + hbformat \ $(HB_UTILS) \ # hbextern \ diff --git a/harbour/utils/hbformat/Makefile b/harbour/utils/hbformat/Makefile new file mode 100644 index 0000000000..11b02430f0 --- /dev/null +++ b/harbour/utils/hbformat/Makefile @@ -0,0 +1,37 @@ +# +# $Id: Makefile 10963 2009-04-30 13:18:04Z druzus $ +# + +ifeq ($(HB_MAIN),) +HB_MAIN = std +endif + +HVMLIB = hbvm +ifneq ($(HB_ARCHITECTURE),dos) +ifneq ($(HB_MT),no) + HVMLIB = hbvmmt +endif +endif + +ROOT = ../../ + +PRG_SOURCES=\ + hbformat.prg \ + +PRG_MAIN=hbformat.prg + +LIBS=\ + hbdebug \ + $(HVMLIB) \ + hbrtl \ + hblang \ + hbcpage \ + hbnulrdd \ + hbrtl \ + $(HVMLIB) \ + hbmacro \ + hbcommon \ + hbpp \ + hbcplr \ + +include $(TOP)$(ROOT)config/bin.cf diff --git a/harbour/utils/hbformat/hbformat.ini b/harbour/utils/hbformat/hbformat.ini new file mode 100644 index 0000000000..43bc5a88a7 --- /dev/null +++ b/harbour/utils/hbformat/hbformat.ini @@ -0,0 +1,90 @@ +# +# $Id: $ +# + +# Eol: -1 - no change, 1 - DOS, 2 - UNIX +#nEol = -1 + +# If yes, converts all tabs to spaces +#lNoTabs = yes + +# If yes, indent code +#lIndent = yes + +# If yes, make case conversion +#lCase = yes + +# If yes, reformat spaces +#lSpaces = yes + +# If yes, indent "Function", "Procedure", "Class", "Method" +#lIndFunc = no + +# If yes, indent "Local", "Private", etc. in a function beginning +#lIndVar = yes + +# If yes, indent directives +#lIndDrt = no + +# If yes, indent "Return" +#lIndRet = yes + +# Leftmost indent - amount of spaces +#nIndLeft = 3 + +# indent - amount of spaces +#nIndNext = 3 + +# Indent for continuation ( after ';' ) lines - amount of spaces +#nIndCont = 3 + +# If yes, convert asterisk '*' to '//' +#lCnvAst = yes + +# If yes, convert '&&' to '//' +#lCnvAmp = yes + +# If yes, convert .NOT. TO ! +#lCnvNot = yes + +# Case of commands ( -1 - no change, 1 - upper, 2 - lower, 3 - title ) +#nCaseCmd = 1 + +# Case of boolean operators ( -1 - no change, 1 - upper, 2 - lower, 3 - title ) +#nCaseBoo = 1 + +# Case of functions ( -1 - no change, 1 - upper, 2 - lower, 3 - title, 4 - as in pattern ) +#nCaseFnc = 4 + +# Case of functions ( -1 - no change, 1 - upper, 2 - lower, 3 - title ) +#nCaseUnk = -1 + +# Case of directives ( -1 - no change, 1 - upper, 2 - lower, 3 - title ) +#nCaseDrt = 2 + +# Number of spaces after # in directives ( -1 - no change ) +nSpaceDrt = 0 + +# -1 - no change, 1 - insert empty line before a function ( procedure,class ) declaration, 2 - remove it +#nLineFnc = 1 + +# -1 - no change, 1 - insert empty line before return, 2 - remove it +#nLineRet = 1 + +# -1 - no change, 1 - insert empty line before variables declaration, 2 - remove it +#nLineVar = 1 + +# -1 - no change, 1 - insert empty line before code in function, 2 - remove it +#nLineCode = 1 + +# Max level of nesting in brackets, while space is added after a comma +#nBr4Comma = 1 + +# Max level of nesting in brackets, while space is added after/before a bracket +#nBr4Brac = 2 + +# Extension for a formatted file ( if empty - replace original ) +#cExtSave = + +# Extension for a backup file +#cExtBack = bak diff --git a/harbour/utils/hbformat/hbformat.prg b/harbour/utils/hbformat/hbformat.prg new file mode 100644 index 0000000000..1d179e3a29 --- /dev/null +++ b/harbour/utils/hbformat/hbformat.prg @@ -0,0 +1,1048 @@ +/* + * $Id: $ + */ + +/* + * Harbour Project source code: + * Harbour source code formatter + * + * Copyright 2009 Alexander S.Kresin + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#include "hbclass.ch" + +#ifndef _CODEFORMAT_EMBEDDED_ + +MEMVAR cFunctions + +FUNCTION MAIN( ... ) + + LOCAL oRef, aParams, cFileName, cInitDir, i, lRecursive := .F. + + // Altd( 2 ); Altd() + aParams := hb_AParams() + + IF Empty( aParams ) .OR. ( Left( cFileName := Atail(aParams ),1 ) $ "@/-" ) + About() + RETURN Nil + ENDIF + + FOR i := 1 TO Len( aParams ) + IF Left( aParams[i], 1 ) $ "-/" + IF SubStr( aParams[i], 2 ) == 'r' + lRecursive := .T. + aParams[i] := '#' + EXIT + ENDIF + ENDIF + NEXT + + oRef := codeFormat():New( aParams ) + IF oRef:nErr > 0 + ? "Initialization error", oRef:nErr, Iif( oRef:nLineErr == 0, "in parameter", "on line " + LTrim( Str(oRef:nLineErr ) ) ), ":", oRef:cLineErr + RETURN Nil + ENDIF + + oRef:bCallBack := { |a, i|FCallBack( a, i ) } + + IF '*' $ cFileName .OR. '?' $ cFileName + cInitDir := Iif( ( i := Rat( '\', cFileName ) ) == 0, ; + Iif( ( i := Rat( '/', cFileName ) ) == 0, ; + '.' + Set( _SET_DIRSEPARATOR ), Left( cFileName, i ) ), ; + Left( cFileName, i ) ) + cFileName := Iif( i == 0, cFileName, SubStr( cFileName, i + 1 ) ) + DirEval( cInitDir, cFileName, lRecursive, { |name|Reformat( oRef,name ) } ) + ELSE + Reformat( oRef, cFileName ) + ENDIF + ? + + RETURN Nil + +STATIC FUNCTION FCallBack( aFile, nItem ) + + LOCAL n := Int( Len( aFile ) / 40 ) + + IF nItem % n == 1 + ?? "." + ENDIF + + RETURN Nil + +STATIC FUNCTION Reformat( oRef, cFileName ) + + LOCAL aFile + + IF !Empty( aFile := oRef:File2Array( cFileName ) ) + ? "Reformatting " + cFileName + ? "<" + Space( 41 ) + ">" + Devpos( Row(), 1 ) + IF oRef:Reformat( aFile ) + oRef:Array2File( cFileName, aFile ) + ELSE + ? "Error", oRef:nErr, "on line", oRef:nLineErr, ":", oRef:cLineErr + ENDIF + ELSE + ? cFileName, "isn't found ..." + ENDIF + + RETURN Nil + +STATIC FUNCTION CmpMsk( strcmp, mask ) + + LOCAL lenm := Len( mask ), i, nPos1 := 1, nPos2, c + + FOR i := 1 TO lenm + c := SubStr( mask, i, 1 ) + IF c == "*" + IF i == lenm + RETURN .T. + ELSE + c := SubStr( mask, i + 1, 1 ) + DO WHILE .T. + nPos2 := At( c, SubStr( strcmp, nPos1 ) ) + IF nPos2 == 0 + RETURN .F. + ENDIF + nPos1 += nPos2 - 1 + IF CmpMsk( SubStr( strcmp, nPos1 ), SubStr( mask, i + 1 ) ) + RETURN .T. + ENDIF + nPos1 ++ + ENDDO + ENDIF + ELSEIF c == "?" + nPos1 ++ + ELSE + IF c != SubStr( strcmp, nPos1, 1 ) + RETURN .F. + ENDIF + nPos1 ++ + ENDIF + NEXT + + RETURN .T. + +FUNCTION DirEval( cInitDir, cMask, lRecur, bCode ) + + LOCAL i, nLen, aFiles + + IF Right( cInitDir, 1 ) != Set( _SET_DIRSEPARATOR ); cInitDir += Set( _SET_DIRSEPARATOR ); ENDIF + cMask := Iif( cMask == Nil, "*.*", Upper( cMask ) ) + + aFiles := Directory( cInitDir + "*.*", "HSD" ) + nLen := Len( aFiles ) + FOR i := 1 TO nLen + IF "D" $ aFiles[ i,5 ] + IF "." != aFiles[ i,1 ] .AND. ".." != aFiles[ i,1 ] .AND. lRecur + DirEval( cInitDir + aFiles[ i,1 ], cMask, lRecur, bCode ) + ENDIF + ELSEIF CmpMsk( Upper( aFiles[ i,1 ] ), cMask ) + IF bCode != Nil + Eval( bCode, cInitDir + aFiles[ i,1 ] ) + ENDIF + ENDIF + NEXT + + RETURN Nil + +STATIC FUNCTION About() + + ? "Harbour source formatter " + Version() + ? "Copyright (c) 2009, Alexander S.Kresin" + ? "http://www.harbour-project.org/" + ? + ? "Syntax: hbformat [options] [@config] file[s]" + ? + + RETURN Nil + +#endif + +CLASS CODEFORMAT + + DATA cEol + DATA nLineErr, nErr, cLineErr + + DATA nEol INIT - 1 // Eol: -1 - no change, 1 - DOS, 2 - UNIX + DATA lNoTabs INIT .T. // If true, converts all tabs to spaces + DATA lIndent INIT .T. // If true, indent code + DATA lCase INIT .T. // If true, make case conversion + DATA lSpaces INIT .T. // If true, reformat spaces + DATA lIndFunc INIT .F. // If true, indent "Function", "Procedure", "Class", "Method" + DATA lIndVar INIT .T. // If true, indent "Local", "Private", etc. in a function beginning + DATA lIndDrt INIT .F. // If true, indent directives + DATA lIndRet INIT .T. // If true, indent "Return" + DATA nIndLeft INIT 3 // Leftmost indent - amount of spaces + DATA nIndNext INIT 3 // indent - amount of spaces + DATA nIndCont INIT 3 // Indent for continuation ( after ';' ) lines - amount of spaces + DATA lCnvAst INIT .T. // If true, convert asterisk '*' to '//' + DATA lCnvAmp INIT .T. // If true, convert '&&' to '//' + DATA lCnvNot INIT .F. // If true, convert .NOT. TO ! + DATA nCaseCmd INIT 1 // Case of commands ( -1 - no change, 1 - upper, 2 - lower, 3 - title ) + DATA nCaseBoo INIT 1 // Case of boolean operators ( -1 - no change, 1 - upper, 2 - lower, 3 - title ) + DATA nCaseFnc INIT 4 // Case of functions ( -1 - no change, 1 - upper, 2 - lower, 3 - title, 4 - as in pattern ) + DATA nCaseUnk INIT - 1 // Case of functions ( -1 - no change, 1 - upper, 2 - lower, 3 - title ) + DATA nCaseDrt INIT 2 // Case of directives ( -1 - no change, 1 - upper, 2 - lower, 3 - title ) + DATA nSpaceDrt INIT 0 // Number of spaces after # in directives ( -1 - no change ) + DATA nLineFnc INIT 1 // -1 - no change, 1 - insert empty line before a function ( procedure,class ) declaration, 2 - remove it + DATA nLineRet INIT 1 // -1 - no change, 1 - insert empty line before return, 2 - remove it + DATA nLineVar INIT 1 // -1 - no change, 1 - insert empty line before variables declaration, 2 - remove it + DATA nLineCode INIT 1 // -1 - no change, 1 - insert empty line before code in function, 2 - remove it + DATA nBr4Comma INIT 1 // Max level of nesting in brackets, while space is added after a comma + DATA nBr4Brac INIT 2 // Max level of nesting in brackets, while space is added after/before a bracket + + DATA cExtSave INIT "" // Extension for a formatted file ( "" - replace original ) + DATA cExtBack INIT "bak" // Extension for a backup file + + DATA cCommands INIT "," + DATA cClauses INIT "," + DATA cFunctions INIT "," + DATA aContr INIT { { "if","","elseif","endif" }, { "do","while","","enddo" }, ; + { "while", "", "", "enddo" }, { "for", "", "", "next" }, { "do", "case", "case", "endcase" }, ; + { "begin", "sequence", "recover", "end" } } + + DATA bCallback + + METHOD New( aParams ) + METHOD SetOption( cLine, i, aIni ) + METHOD ReadIni( cIniName ) + METHOD Reformat( aFile ) + METHOD FormatLine( cLine ) + METHOD ConvertCmd( cLine, nBegin, nEnd ) + METHOD ConvertFnc( cLine, nBegin, nEnd ) + METHOD ConvertBool( cLine, nBegin, nEnd ) + METHOD File2Array( cFileName ) + METHOD Array2File( cFileName, aFile ) + +ENDCLASS + +METHOD New( aParams ) CLASS CODEFORMAT + + LOCAL i, cParam, cIniName := rf_FullPath() + + ::nErr := 0 + cIniName := Iif( ( i := Rat( '\', cIniName ) ) = 0, ; + Iif( ( i := Rat( '/', cIniName ) ) = 0, "", Left( cIniName, i ) ), ; + Left( cIniName, i ) ) + "hbformat.ini" + IF !::ReadIni( cIniName ) + RETURN Self + ENDIF + FOR i := 1 TO Len( aParams ) + IF Left( cParam := aParams[i], 1 ) == "@" + IF !::ReadIni( SubStr( cParam,2 ) ) + RETURN Self + ENDIF + ELSEIF Left( cParam, 1 ) $ "-/" + IF !::SetOption( SubStr( cParam,2 ), 0 ) + RETURN Self + ENDIF + ENDIF + NEXT + + IF Right( ::cCommands, 1 ) != "," + ::cCommands += "," + ENDIF + ::cCommands += "IF,ELSEIF,ELSE,ENDIF,END,DO,WHILE,ENDDO,WITH,CASE,OTHERWISE,ENDCASE,BEGIN," + ::cCommands += "FUNCTION,PROCEDURE,RETURN,CLASS,ENDCLASS,METHOD,DATA,LOCAL,PRIVATE,PUBLIC,STATIC,FIELD,MEMVAR,PARAMETERS,DECLARE," + ::cCommands += "ACCEPT,APPEND,AVERAGE,CLEAR,CLOSE,COMMIT,CONTINUE,COPY,COUNT,CREATE,DEFAULT," + ::cCommands += "DELETE,DISPLAY,EJECT,ERASE,EXIT,GO,GOTO,INDEX,INPUT,JOIN,KEYBOARD,LABEL,LIST,LOCATE," + ::cCommands += "LOOP,MENU,PACK,PRINT,QUIT,READ,RECALL,REINDEX,RELEASE,RENAME,REQUEST,REPLACE,RESTORE," + ::cCommands += "RUN,SAVE,SEEK,SELECT,SET,SKIP,SORT,STORE,SUM,TEXT,TOTAL,UNLOCK,USE,WAIT,ZAP," + + IF Right( ::cClauses, 1 ) != "," + ::cClauses += "," + ENDIF + ::cClauses += "ADDITIVE,ALIAS,ALL,BLANK,BOTTOM,BOX,COLOR,DATE,DELETED,EACH,EXTENDED,EXCLUSIVE,FROM,GET," + ::cClauses += "RANGE,READONLY,REST,SAY,SCREEN,ALTERNATE,BELL,CENTURY,CONFIRM,CONSOLE,CURSOR,DECIMALS,DELIMITERS,DEVICE,EPOCH,ESCAPE," + ::cClauses += "EXACT,EXCLUSIVE,FILTER,FIXED,FORMAT,INTENSITY,KEY,LIKE,MARGIN,MESSAGE,NEW,OFF,ON,ORDER,PATH,PICTURE,PRINTER,PROMPT," + ::cClauses += "PROTECTED,RELATION,SCOREBOARD,SEQUENCE,SOFTSEEK,STEP,STRUCTURE,TYPEAHEAD,UNIQUE,WRAP,TAG,TO,TOP,VALID,WHEN," + + IF Right( ::cFunctions, 1 ) != "," + ::cFunctions += "," + ENDIF + IF ! ( ",STR," $ Upper( ::cFunctions ) ) + ::cFunctions += "AAdd,Abs,AChoice,AClone,ACopy,ADel,ADir,AEval,AFields,AFill,AIns,Alert,Alias,AllTrim,Altd," + ::cFunctions += "Array,Asc,ASize,ASort,At,Bin2i,Bin2l,Bin2w,Bof,Browse,Cdow,Chr,Cmonth,Col,Ctod,Curdir," + ::cFunctions += "Date,Day,dbAppend,dbClearFil,dbClearInd,dbCloseAll,dbCloseArea,dbCommit,dbCreate,dbDelete,dbEdit,dbEval,Dbf,dbFilter,dbGoBottom,dbGoto,dbRecall,dbReindex,dbRelation,dbRLock,dbRSelect,dbRunLock," + ::cFunctions += "dbSeek,dbSelectArea,dbSetDriver,dbSetFilter,dbSetIndex,dbSetOrder,dbSetRelat,dbSkip,dbStruct,dbUnlock,dbUseArea,Deleted,Descend,Devout,Devpos," + ::cFunctions += "Directory,DiskSpace,DispBegin,DispBox,DispCount,DispEnd,DispOut,DosError,Dow,Dtoc,Dtos,Empty,Eof,Errorblock,Errorlevel,Eval,Exp,FClose,FCount,FCreate,FErase,FError,FieldBlock,FieldGet,FieldName," + ::cFunctions += "FieldPos,FieldPut,Fieldwblock,File,Fklabel,Fkmax,FLock,FOpen,Found,FRead,FReadstr,FRename,FSeek,FWrite,Getenv,Hardcr,Header,Iif,IndexExt,IndexKey,IndexOrd,Inkey,Int,Isalpha,Isarray,Ischaracter," + ::cFunctions += "IsDate,IsDigit,IsLogic,IsLower,IsNumber,IsPrinter,IsUpper,I2bin,L2bin,LastKey,LastRec,Left,Len,Lower,LTrim,LUpdate,MakeDir,Max,MaxCol,MaxRow,MCol,MemoEdit,MemoLine,MemoRead," + ::cFunctions += "Memory,MemoTran,MemoWrite,MemvarBlock,Min,Mlcount,Mlctopos,Mlpos,Mod,Month,Mpostolc,NetErr,NetName,NextKey,Nosnow,Os,OrdBagExt,OrdBagName,OrdCreate,OrdDestroy,OrdFor,OrdKey,OrdListAdd," + ::cFunctions += "OrdListClear,OrdListRebuild,OrdName,OrdNumber,OrdSetFocus,OutErr,OutStd,Pad,PadR,PadL,PCol,PCount,ProcLine,ProcName,PRow,QQout,Qout,Rat,Rddlist,Rddname,Rddsetdefault,Readexit,Readinsert,Readkey," + ::cFunctions += "ReadModal,ReadVar,RecCount,RecNo,RecSize,Replicate,RestScreen,Right,RLock,Round,Row,RTrim,SaveScreen,Scroll,Seconds,Select,Set,Setblink,Setcancel,Setcolor,Setcursor,Setkey,Setmode,Setpos,Setprc," + ::cFunctions += "Soundex,Space,Sqrt,Str,StrZero,StrTran,Stuff,SubStr,Time,Tone,Transform,Trim,Type,Updated,Upper,Used,Val,ValType,Version,Word,Year," + ENDIF + + IF ::nEol == 2 + ::cEol := Chr( 10 ) + ELSEIF ::nEol > 0 + ::cEol := Chr( 13 ) + Chr( 10 ) + ENDIF + IF ::lIndent + ::lNoTabs := .T. + ENDIF + + RETURN Self + +#define RF_STATE_FUNC 1 + +#define RF_STATE_VAR 2 + +#define RF_STATE_CODE 3 + +#define RF_STATE_RET 4 + +METHOD Reformat( aFile ) CLASS CODEFORMAT + + LOCAL i, nLen := Len( aFile ), cToken1, cToken2, nPos + LOCAL nPosSep, cLine, cLineAll, nLineSegment + LOCAL nContrState, nIndent, nDeep := 0, aDeep := {} + LOCAL lPragmaDump := .F. , lClass := .F. , lComment := .F. , nPosComment + LOCAL nStatePrev, nState := 0 + PRIVATE cFunctions := Upper( ::cFunctions ) + + ::nErr := 0 + FOR i := 1 TO nLen + IF aFile[i] == Nil + EXIT + ENDIF + IF ::bCallBack != Nil + Eval( ::bCallBack, aFile, i ) + ENDIF + nPosComment := 0 + IF ::lIndent + aFile[i] := StrTran( RTrim( aFile[i] ), Chr( 9 ), " " ) + ELSE + aFile[i] := RTrim( aFile[i] ) + ENDIF + + IF Empty( aFile[i] ) + aFile[i] := "" + LOOP + ENDIF + IF lComment + IF ( nPos := FindNotQuoted( "*/", aFile[i] ) ) != 0 + lComment := .F. + IF !Empty( cToken1 := SubStr( aFile[i], nPos + 2 ) ) + aFile[i] := Left( aFile[i], nPos + 1 ) + nLen := rf_AINS( aFile, i + 1, cToken1 ) + ENDIF + ENDIF + ELSE + cLineAll := LTrim( aFile[i] ) + IF Left( cLineAll, 1 ) == "#" + cToken1 := Lower( hb_TokenGet( cLineAll, 1 ) ) + cToken2 := Lower( hb_TokenGet( cLineAll, 2 ) ) + IF Len( cToken1 ) == 1 + cToken1 += cToken2 + cToken2 := Lower( hb_TokenGet( cLineAll, 3 ) ) + ENDIF + IF cToken1 == "#pragma" + IF cToken2 == "begindump" + lPragmaDump := .T. + ELSEIF cToken2 == "enddump" + lPragmaDump := .F. + ENDIF + ENDIF + ENDIF + IF Left( cLineAll, 1 ) == "*" + nPosComment := 1 + IF ::lCnvAst + cLineAll := "//" + SubStr( cLineAll, 2 ) + ENDIF + ELSEIF ( nPos := FindNotQuoted( "//", cLineAll ) ) != 0 + nPosComment := nPos + ELSEIF ( nPos := FindNotQuoted( "&&", cLineAll ) ) != 0 + nPosComment := nPos + IF ::lCnvAmp + cLineAll := Left( cLineAll, nPos - 1 ) + "//" + SubStr( cLineAll, nPos + 2 ) + ENDIF + ENDIF + IF ( nPos := FindNotQuoted( "/*", cLineAll ) ) != 0 .AND. ( nPosComment == 0 .OR. nPosComment > nPos ) + nPosComment := nPos + IF ( nPos := FindNotQuoted( "*/", cLineAll, nPos + 2 ) ) != 0 + IF !Empty( cToken1 := SubStr( cLineAll, nPos + 2 ) ) + cLineAll := Left( cLineAll, nPos + 1 ) + nLen := rf_AINS( aFile, i + 1, cToken1 ) + ENDIF + ELSE + lComment := .T. + ENDIF + ENDIF + IF !lPragmaDump .AND. ::lIndent .AND. ( !lComment .OR. nPosComment > 1 ) + aFile[i] := cLineAll + IF i == 1 .OR. Right( aFile[i-1], 1 ) != ';' + nPosSep := 1 + nLineSegment := 1 + DO WHILE .T. + nPos := nPosSep + IF ( nPosSep := FindNotQuoted( ";", aFile[i], nPosSep ) ) != 0 .AND. ; + nPosSep < Len( aFile[i] ) .AND. ( nPosComment == 0 .OR. nPosSep < nPosComment ) + cLine := SubStr( aFile[i], nPos, nPosSep - nPos + 1 ) + ELSE + nPosSep := 0 + cLine := SubStr( aFile[i], nPos, Len( aFile[i] ) - nPos + 1 ) + ENDIF + + nContrState := 0 + nStatePrev := nState + cToken1 := Lower( hb_TokenGet( cLine, 1 ) ) + cToken2 := Lower( hb_TokenGet( cLine, 2 ) ) + IF Left( cToken1, 1 ) == '#' + ELSEIF ( "static" = cToken1 .AND. ; + ( "function" = cToken2 .OR. "procedure" = cToken2 ) ) .OR. ; + "function" = cToken1 .OR. "procedure" = cToken1 ; + .OR. ( "method" == cToken1 .AND. !lClass ) .OR. ; + ( "class" == cToken1 .AND. !lClass ) + IF nDeep == 0 + nState := RF_STATE_FUNC + IF "class" == cToken1 + lClass := .T. + ENDIF + ELSE + ::nLineErr := i + ::nErr := 1 + ::cLineErr := cLine + RETURN .F. + ENDIF + ELSEIF "local" = cToken1 .OR. "private" = cToken1 ; + .OR. "public" = cToken1 .OR. "field" = cToken1 ; + .OR. "static" = cToken1 .OR. "memvar" = cToken1 ; + .OR. "parameters" = cToken1 .OR. "declare" = cToken1 + IF nStatePrev == RF_STATE_FUNC + nState := RF_STATE_VAR + ENDIF + ELSEIF cToken1 == "return" .OR. cToken1 == "endclass" + IF nDeep == 0 + nState := RF_STATE_RET + ENDIF + ELSE + IF !( cToken1 == "request" ) + nState := RF_STATE_CODE + ENDIF + IF ( nContrState := Ascan( ::aContr, ; + { |a|a[1] == cToken1 .AND. ( Empty( a[2] ) .OR. a[2] == cToken2 ) } ) ) != 0 + IF Len( aDeep ) < ++ nDeep + AAdd( aDeep, Nil ) + ENDIF + aDeep[nDeep] := nContrState + ELSEIF Len( cToken1 ) < 4 .OR. ( nContrState := Ascan( ::aContr,{ |a|a[3] = cToken1 } ) ) == 0 + IF ( nPos := Ascan( ::aContr,{ |a|a[4] == cToken1 } ) ) > 0 .OR. ; + cToken1 == "end" + IF nPos != 0 .AND. nDeep > 0 .AND. aDeep[nDeep] != nPos + DO WHILE ( nPos := Ascan( ::aContr, { |a|a[4] == cToken1 }, ; + nPos ) ) != 0 .AND. aDeep[nDeep] != nPos + ENDDO + ENDIF + IF nDeep > 0 .AND. aDeep[nDeep] == nPos .OR. cToken1 == "end" + nDeep -- + ELSE + ::nLineErr := i + ::nErr := 3 + ::cLineErr := cLine + RETURN .F. + ENDIF + ENDIF + ENDIF + ENDIF + IF nLineSegment == 1 + IF nState == 0 + nIndent := 0 + ELSEIF nState == RF_STATE_FUNC + nIndent := Iif( ::lIndFunc, ::nIndLeft, 0 ) + ELSEIF nState == RF_STATE_VAR + nIndent := Iif( ::lIndVar, ::nIndLeft, 0 ) + ELSEIF nState == RF_STATE_RET + nIndent := Iif( !lClass .AND. ::lIndRet, ::nIndLeft, 0 ) + ELSE + nIndent := ::nIndLeft + ::nIndNext * Iif( nContrState == 0, nDeep, nDeep - 1 ) + ENDIF + IF Left( cLine, 1 ) == "#" .AND. !::lIndDrt + nIndent := 0 + ENDIF + cLineAll := Space( nIndent ) + ::FormatLine( cLine ) + + IF i > 1 .AND. ( ( nState == RF_STATE_RET .AND. ::nLineRet > 0 ) .OR. ; + ( nState == RF_STATE_FUNC .AND. ::nLineFnc > 0 ) .OR. ; + ( nState == RF_STATE_VAR .AND. nStatePrev != nState .AND. ::nLineVar > 0 ) .OR. ; + ( nState == RF_STATE_CODE .AND. nStatePrev != nState .AND. ::nLineCode > 0 ) ) + nPos := i - 1 + IF ( nState == RF_STATE_RET .AND. ::nLineRet == 1 ) .OR. ; + ( nState == RF_STATE_FUNC .AND. ::nLineFnc == 1 ) .OR. ; + ( nState == RF_STATE_VAR .AND. ::nLineVar == 1 ) .OR. ; + ( nState == RF_STATE_CODE .AND. ::nLineCode == 1 ) + IF !Empty( aFile[nPos] ) + nLen := rf_AINS( aFile, nPos + 1, "" ) + i ++ + ELSE + nPos -- + ENDIF + ENDIF + DO WHILE nPos > 1 .AND. Empty( aFile[nPos] ) + rf_ADEL( aFile, nPos ) + i -- + nPos -- + ENDDO + ENDIF + ELSE + cLineAll += ::FormatLine( cLine ) + ENDIF + IF lClass .AND. nState == RF_STATE_RET + lClass := .F. + ENDIF + IF nPosSep == 0 .OR. nPosSep == Len( aFile[i] ) + EXIT + ENDIF + nPosSep ++ + nLineSegment ++ + ENDDO + aFile[i] := cLineAll + ELSE + // This line is a continuation of previous + aFile[i] := Space( ::nIndLeft + ::nIndNext * nDeep + ::nIndCont ) + ::FormatLine( aFile[i], .T. ) + ENDIF + ELSEIF !lPragmaDump + aFile[i] := ::FormatLine( aFile[i] ) + ENDIF + ENDIF + NEXT + + RETURN .T. + +#define FL_STATE_DIGIT 1 + +#define FL_STATE_ANY 2 + +#define FL_STATE_OP 3 + +#define FL_STATE_STRING 4 + +#define FL_STATE_QUOTED 11 + +#define FL_STATE_SQBR 12 + +METHOD FormatLine( cLine, lContinued ) CLASS CODEFORMAT + + LOCAL i, nLen, c, nState := 0, cSymb, cToken, nPos := 1 + LOCAL lFirst, nBegin, nEnd, nB := 0, nA := 0, aBrackets[2] + LOCAL cOperators := "+-*/%#=~^<>$!" + + IF !::lCase .AND. !::lSpaces + RETURN cLine + ENDIF + + IF lContinued == Nil; lContinued := .F. ; ENDIF + lFirst := !lContinued + + nLen := Len( cLine ) + + DO WHILE SubStr( cLine, nPos, 1 ) == ' '; nPos ++ ; ENDDO + + IF !lContinued .AND. Left( cLine, 1 ) == '#' + IF ::lSpaces .AND. ::nSpaceDrt != - 1 + cLine := Left( cLine, nPos ) + Space( ::nSpaceDrt ) + LTrim( SubStr( cLine, nPos + 1 ) ) + ENDIF + nLen := Len( cLine ) + IF ::lCase .AND. ::nCaseDrt != - 1 + nPos ++ + DO WHILE SubStr( cLine, nPos, 1 ) == ' '; nPos ++ ; ENDDO + i := nPos + DO WHILE nPos <= nLen .AND. SubStr( cLine, nPos, 1 ) >= 'A'; nPos ++ ; ENDDO + IF SubStr( cLine, nPos, 1 ) >= 'A' + nPos ++ + ENDIF + cToken := SubStr( cLine, i, nPos - i ) + cToken := Iif( ::nCaseDrt == 1, Upper( cToken ), Iif( ::nCaseDrt == 2, Lower(cToken ),Upper(Left(cToken,1 ) ) + Lower(SubStr(cToken,2 ) ) ) ) + cLine := Left( cLine, i - 1 ) + cToken + Iif( nPos > nLen, "", SubStr( cLine, nPos ) ) + ENDIF + ELSE + aBrackets[1] := aBrackets[2] := 0 + FOR i := nPos TO nLen + c := SubStr( cLine, i, 1 ) + IF nState <= FL_STATE_STRING + IF ( c >= '0' .AND. c <= '9' ) .OR. ( c >= 'A' .AND. c <= 'Z' ) ; + .OR. ( c >= 'a' .AND. c <= 'z' ) .OR. c == '_' + IF nState < FL_STATE_STRING .OR. ( nState == FL_STATE_STRING .AND. nEnd > nBegin ) + IF nState == FL_STATE_STRING + ::ConvertCmd( @cLine, nBegin, nEnd ) + ENDIF + IF c >= 'A' + nState := FL_STATE_STRING + nBegin := nEnd := i + ELSE + nState := FL_STATE_DIGIT + ENDIF + ENDIF + ELSEIF c == '"' .OR. c == "'" + IF nState == FL_STATE_STRING + IF nEnd == nBegin + nEnd := i + ENDIF + ::ConvertCmd( @cLine, nBegin, nEnd ) + ENDIF + cSymb := c + nState := FL_STATE_QUOTED + ELSEIF c == '[' + nState := FL_STATE_SQBR + ELSEIF c == '/' .AND. ( ( c := SubStr( cLine, i + 1, 1 ) ) == '/' .OR. c == '*' ) + IF nState == FL_STATE_STRING + IF nEnd == nBegin + nEnd := i + ENDIF + ::ConvertCmd( @cLine, nBegin, nEnd ) + ENDIF + EXIT + ELSEIF c == ' ' + nEnd := i + i ++ + DO WHILE i <= nLen .AND. SubStr( cLine, i, 1 ) == ' '; i ++ ; ENDDO + i -- + ELSEIF c == '(' .OR. c == '{' + aBrackets[ Iif( c=='(', 1, 2 ) ] ++ + IF nState == FL_STATE_STRING + IF nEnd == nBegin + nEnd := i + ENDIF + IF ( !lFirst .OR. !::ConvertCmd( @cLine,nBegin,nEnd, .T. ) ) .AND. c == '(' + ::ConvertFnc( @cLine, nBegin, nEnd ) + ENDIF + ENDIF + IF ::lSpaces .AND. aBrackets[ Iif( c=='(', 1, 2 ) ] <= ::nBr4Brac .AND. ; + i < nLen .AND. !( SubStr( cLine,i + 1,1 ) $ " )}" ) + nA := i + ENDIF + nState := FL_STATE_ANY + ELSEIF c == '.' + IF nState == FL_STATE_STRING + IF nBegin > 1 .AND. SubStr( cLine, nBegin - 1, 1 ) == '.' .AND. nEnd == nBegin + ::ConvertBool( @cLine, nBegin, i ) + IF Len( cLine ) != nLen + /* If .not. was converted to ! */ + i -= ( nLen - Len( cLine ) ) + nLen := Len( cLine ) + ELSE + nB := nBegin - 1 + nA := i + ENDIF + ELSE + IF nEnd == nBegin + nEnd := i + ENDIF + ::ConvertCmd( @cLine, nBegin, nEnd ) + ENDIF + ENDIF + nState := FL_STATE_ANY + ELSEIF c == ',' + IF aBrackets[1] <= ::nBr4Comma .AND. aBrackets[2] <= ::nBr4Comma + nA := i + ENDIF + nState := FL_STATE_ANY + ELSEIF c == '!' .AND. SubStr( cLine, i + 1, 1 ) != '=' + IF nState == FL_STATE_STRING + IF nEnd == nBegin + nEnd := i + ENDIF + ::ConvertCmd( @cLine, nBegin, nEnd ) + ENDIF + nState := Iif( SubStr( cLine,i + 1,1 ) == '=', FL_STATE_OP, FL_STATE_ANY ) + ELSEIF c $ cOperators .OR. ( c == ':' .AND. SubStr( cLine,i + 1,1 ) == '=' ) + nB := i + IF SubStr( cLine, i + 1, 1 ) $ cOperators + i ++ + ENDIF + nA := i + nState := FL_STATE_OP + ELSEIF c == ')' .OR. c == '}' + IF ::lSpaces .AND. aBrackets[ Iif( c=='(', 1, 2 ) ] <= ::nBr4Brac .AND. ; + i > 1 .AND. !( SubStr( cLine,i - 1,1 ) $ ' ({' ) + nB := i + ENDIF + aBrackets[ Iif( c==')', 1, 2 ) ] -- + nState := FL_STATE_ANY + ELSE + nState := FL_STATE_ANY + ENDIF + IF lFirst .AND. nState != FL_STATE_STRING + lFirst := .F. + ENDIF + IF nA != 0 .AND. ::lSpaces .AND. nA < nLen .AND. SubStr( cLine, nA + 1, 1 ) != ' ' + cLine := Left( cLine, nA ) + ' ' + SubStr( cLine, nA + 1 ) + nLen ++ + i ++ + ENDIF + IF nB != 0 .AND. ::lSpaces .AND. nB > 1 .AND. SubStr( cLine, nB - 1, 1 ) != ' ' + cLine := Left( cLine, nB - 1 ) + ' ' + SubStr( cLine, nB ) + nLen ++ + i ++ + ENDIF + nA := nB := 0 + ELSEIF ( nState == FL_STATE_QUOTED .AND. c == cSymb ) .OR. ; + ( nState == FL_STATE_SQBR .AND. c == ']' ) + nState := FL_STATE_ANY + ENDIF + IF i == nLen .AND. lFirst .AND. nState == FL_STATE_STRING + i ++ + ::ConvertCmd( @cLine, nBegin, i ) + ENDIF + NEXT + ENDIF + + RETURN cLine + +METHOD ConvertCmd( cLine, nBegin, nEnd, lFirstOnly ) CLASS CODEFORMAT + + LOCAL nPos, cToken := Upper( SubStr( cLine, nBegin, nEnd - nBegin ) ) + + IF ::lCase + IF lFirstOnly == Nil; lFirstOnly := .F. ; ENDIF + IF ( ( nPos := At( "," + cToken, ::cCommands ) ) != 0 .AND. ( Len(cToken ) >= 4 ; + .OR. SubStr( ::cCommands, nPos + Len( cToken ) + 1, 1 ) == ',' ) ) ; + .OR. ; + ( !lFirstOnly .AND. ; + ( nPos := At( "," + cToken, ::cClauses ) ) != 0 .AND. ( Len( cToken ) >= 4 ; + .OR. SubStr( ::cClauses, nPos + Len( cToken ) + 1, 1 ) == ',' ) ) + IF ::nCaseCmd > 0 + IF ::nCaseCmd > 1 + cToken := Iif( ::nCaseCmd == 2, Lower( cToken ), Left( cToken,1 ) + ; + Lower( SubStr( cToken,2 ) ) ) + ENDIF + cLine := Iif( nBegin == 1, cToken + SubStr( cLine, nEnd ), ; + Left( cLine, nBegin - 1 ) + cToken + SubStr( cLine, nEnd ) ) + ENDIF + ELSE + RETURN .F. + ENDIF + ENDIF + + RETURN .T. + +METHOD ConvertFnc( cLine, nBegin, nEnd ) CLASS CODEFORMAT + + LOCAL nPos, cToken := Upper( SubStr( cLine, nBegin, nEnd - nBegin ) ) + + IF ::lCase .AND. ::nCaseFnc > 0 + IF ( nPos := At( "," + cToken + ",", m -> cFunctions ) ) != 0 + + IF ::nCaseFnc > 1 + nPos ++ + cToken := Iif( ::nCaseFnc == 2, Lower( cToken ), Iif( ::nCaseFnc == 3, ; + Left( cToken, 1 ) + Lower( SubStr( cToken,2 ) ), ; + SubStr( ::cFunctions, nPos, Len( cToken ) ) ) ) + ENDIF + cLine := Iif( nBegin == 1, cToken + SubStr( cLine, nEnd ), ; + Left( cLine, nBegin - 1 ) + cToken + SubStr( cLine, nEnd ) ) + ELSEIF ::nCaseUnk > 0 + cToken := Iif( ::nCaseUnk == 2, Lower( cToken ), ; + Left( cToken, 1 ) + Lower( SubStr( cToken,2 ) ) ) + cLine := Iif( nBegin == 1, cToken + SubStr( cLine, nEnd ), ; + Left( cLine, nBegin - 1 ) + cToken + SubStr( cLine, nEnd ) ) + ENDIF + ENDIF + + RETURN .T. + +METHOD ConvertBool( cLine, nBegin, nEnd ) CLASS CODEFORMAT + + LOCAL cBool := ",NOT,AND,OR,F,T," + LOCAL nPos, cToken := Upper( SubStr( cLine, nBegin, nEnd - nBegin ) ) + + IF ::lCase + IF ( nPos := At( "," + cToken + ",", cBool ) ) != 0 + IF ::lCnvNot .AND. nPos == 1 + cLine := Left( cLine, nBegin - 2 ) + '!' + SubStr( cLine, nEnd + 1 ) + ELSE + IF ::nCaseBoo > 0 + IF ::nCaseBoo > 1 + cToken := Iif( ::nCaseBoo == 2, Lower( cToken ), Left( cToken,1 ) + ; + Lower( SubStr( cToken,2 ) ) ) + ENDIF + cLine := Left( cLine, nBegin - 1 ) + cToken + SubStr( cLine, nEnd ) + ENDIF + ENDIF + ELSE + RETURN .F. + ENDIF + ENDIF + + RETURN .T. + +METHOD SetOption( cLine, i, aIni ) CLASS CODEFORMAT + + LOCAL nPos, cToken1, cToken2, cTemp, xRes + + IF ( nPos := At( "=", cLine ) ) != 0 + cToken1 := Upper( RTrim( Left( cLine, nPos - 1 ) ) ) + cToken2 := LTrim( SubStr( cLine, nPos + 1 ) ) + IF __ObjHasMsg( Self, cToken1 ) + IF Empty( cToken2 ) + xRes := "" + ELSEIF IsDigit( cToken2 ) + xRes := Val( cToken2 ) + ELSEIF Isalpha( cToken2 ) + IF ( cTemp := Upper( cToken2 ) ) == "ON" .OR. cTemp == "YES" + xRes := .T. + ELSEIF cTemp == "OFF" .OR. cTemp == "NO" + xRes := .F. + ELSE + IF Right( cToken2, 1 ) == ";" .AND. aIni != Nil + xRes := RTrim( Left( cToken2, Len(cToken2 ) - 1 ) ) + DO WHILE ++ i < Len( aIni ) + IF Right( aIni[i], 1 ) == ";" + xRes += AllTrim( Left( aIni[i],Len(aIni ) - 1 ) ) + ELSE + xRes += AllTrim( aIni[i] ) + EXIT + ENDIF + ENDDO + ELSE + xRes := cToken2 + ENDIF + ENDIF + ELSE + ::nErr := 3 + ENDIF + IF ::nErr == 0 .AND. ValType( xRes ) != Left( cToken1, 1 ) + ::nErr := 4 + ENDIF + ELSE + ::nErr := 2 + ENDIF + ELSE + ::nErr := 1 + ENDIF + IF ::nErr == 0 + __objSendMsg( Self, "_" + cToken1, xRes ) + ELSE + ::nLineErr := i + ::cLineErr := cLine + ENDIF + + RETURN ( ::nErr == 0 ) + +METHOD ReadIni( cIniName ) CLASS CODEFORMAT + + LOCAL i, nLen, aIni, c + + IF hb_FileExists( cIniName ) + aIni := rf_FileRead( MemoRead( cIniName ) ) + nLen := Len( aIni ) + FOR i := 1 TO nLen + IF !Empty( aIni[i] := AllTrim( aIni[i] ) ) .AND. ; + ( c := Left( aIni[i],1 ) ) != ';' .AND. c != '#' + IF !::SetOption( aIni[i], @i, aIni ) + EXIT + ENDIF + ENDIF + NEXT + ENDIF + + RETURN ( ::nErr == 0 ) + +METHOD File2Array( cFileName ) CLASS CODEFORMAT + + LOCAL aFile, cEol + + IF hb_FileExists( cFileName ) + aFile := rf_FileRead( MemoRead( cFileName ), @cEol ) + IF ::nEol <= 0 + ::cEol := cEol + ENDIF + ENDIF + + RETURN aFile + +METHOD Array2File( cFileName, aFile ) CLASS CODEFORMAT + + LOCAL handle, i, nLen := Len( aFile ), cName, cBakName + + cName := Iif( ( i := Rat('.',cFileName ) ) == 0, cFileName, SubStr( cFileName,1,i - 1 ) ) + IF Empty( ::cExtSave ) + cBakName := cName + Iif( Left( ::cExtBack,1 ) != '.', '.', "" ) + ::cExtBack + IF FRename( cFileName, cBakName ) == - 1 + RETURN .F. + ENDIF + ENDIF + + IF !Empty( ::cExtSave ) + cFileName := cName + Iif( Left( ::cExtSave,1 ) != '.', '.', "" ) + ::cExtSave + ENDIF + handle := FCreate( cFileName ) + FOR i := 1 TO nLen + IF aFile[i] == Nil + EXIT + ENDIF + IF i < nLen .OR. !Empty( aFile[i] ) + FWrite( handle, aFile[i] + ::cEol ) + ENDIF + NEXT + FClose( handle ) + + RETURN .T. + +STATIC FUNCTION rf_AINS( arr, nItem, cItem ) + + IF Atail( arr ) != Nil + AAdd( arr, Nil ) + ENDIF + AIns( arr, nItem ) + arr[nItem] := cItem + + RETURN Len( arr ) + +STATIC FUNCTION rf_ADEL( arr, nItem ) + + ADel( arr, nItem ) + + RETURN Nil + +#ifdef __XHARBOUR__ + +#xtranslate HB_AT( < x, ... > ) => At( < x > ) + +#endif + +STATIC FUNCTION FindNotQuoted( subs, stroka, nPos2 ) + + LOCAL nPos1, i, c, nState := 0, cSymb + + IF nPos2 == Nil; nPos2 := 1; ENDIF + DO WHILE .T. + IF ( nPos1 := hb_At( subs, stroka, nPos2 ) ) == 0 + EXIT + ENDIF + FOR i := nPos2 TO nPos1 - 1 + c := SubStr( stroka, i, 1 ) + IF nState == 0 + IF c == '"' .OR. c == "'" + cSymb := c + nState := 1 + ELSEIF c == '[' + nState := 2 + ENDIF + ELSEIF ( nState == 1 .AND. c == cSymb ) .OR. ( nState == 2 .AND. c == ']' ) + nState := 0 + ENDIF + NEXT + IF nState == 0 + EXIT + ENDIF + nPos2 := nPos1 + 1 + ENDDO + + RETURN nPos1 + +#pragma BEGINDUMP +#include "hbapi.h" +#include "hbapiitm.h" + +/* rf_FileRead( cText, @cEol ) */ +HB_FUNC( RF_FILEREAD ) +{ + char * szText = hb_parc( 1 ); + char * ptr, * ptr1; + unsigned long ul, ulLines = 0; + PHB_ITEM temp; + PHB_ITEM arr; + + ptr = szText; + while( *ptr ) + { + if( *ptr == '\r' || *ptr == '\n' ) + { + if( !ulLines ) + { + if ISBYREF( 2 ) + hb_storclen( ptr, ( *(ptr+1) == '\r' || *(ptr+1) == '\n' )? 2:1, 2 ); + } + if( *(ptr+1) == '\r' || *(ptr+1) == '\n' ) + { + ptr ++; + } + ulLines ++; + } + ptr ++; + } + ptr --; + if( *ptr != '\r' && *ptr != '\n' ) + ulLines ++; + + arr = hb_itemArrayNew( ulLines ); + + ptr = ptr1 = szText; + ul = 1; + while( *ptr ) + { + if( *ptr == '\r' || *ptr == '\n' ) + { + temp = hb_itemPutCL( NULL, ptr1, ptr - ptr1 ); + hb_itemArrayPut( arr, ul, temp ); + hb_itemRelease( temp ); + + if( *(ptr+1) == '\r' || *(ptr+1) == '\n' ) + { + ptr ++; + } + ptr1 = ptr + 1; + ul ++; + } + ptr ++; + } + if( ul == ulLines ) + { + temp = hb_itemPutCL( NULL, ptr1, ptr - ptr1 ); + hb_itemArrayPut( arr, ul, temp ); + hb_itemRelease( temp ); + } + hb_itemReturn( arr ); + hb_itemRelease( arr ); +} + +HB_FUNC( RF_FULLPATH ) +{ + hb_retc( hb_cmdargARGV()[0] ); +} + +#pragma ENDDUMP