diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 62be682c36..266c60fb1b 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,18 @@ past entries belonging to author(s): Viktor Szakats. */ +2009-07-01 10:53 UTC+0600 April White (april users.sourceforge.net) + * examples/hbextern/hbextern.hbp + * build flags + * examples/hbextern/hbextern.prg + * significant updates + ; default params works mostly like original version + ; TOFIX: produces this 'bad' code (harbour reports "hbextern.ch_(1019) Error E0025 Error in #if expression" + #if ZLIB_VERNUM >= 0x1230 + EXTERNAL HB_GZDIRECT + #endif /* #if ZLIB_VERNUM >= 0x1230 */ + % Question: do I upload a new hbextern.ch or can/should a user with more experience with it do so? + 2009-07-01 14:51 UTC+0200 Viktor Szakats (harbour.01 syenar.hu) * contrib/hbqt/hbqt.h - Deleted some unncessary #includes. (done again) diff --git a/harbour/examples/hbextern/hbextern.hbp b/harbour/examples/hbextern/hbextern.hbp index 9dabc5b604..8b1b11dd81 100644 --- a/harbour/examples/hbextern/hbextern.hbp +++ b/harbour/examples/hbextern/hbextern.hbp @@ -2,6 +2,10 @@ # $Id$ # +-q0 +-w2 +-es2 + -nulrdd hbextern.prg diff --git a/harbour/examples/hbextern/hbextern.prg b/harbour/examples/hbextern/hbextern.prg index 64581fb230..9be95d89ac 100644 --- a/harbour/examples/hbextern/hbextern.prg +++ b/harbour/examples/hbextern/hbextern.prg @@ -78,12 +78,19 @@ REQUEST HB_GT_CGI_DEFAULT #endif // List of known files which does not contain any real public function. -STATIC s_aSkipFiles := { "profiler.prg" } -STATIC s_aSkipDirs := { "tests", "example", "examples", "sample", "samples", ".svn", "%HB_ARCHITECTURE%", "codepage" } -STATIC s_aSkipNames := { "MAIN" } // Init with names you want to skip +STATIC s_aSkipFiles := { "profiler.prg", "msg_tpl.c" } +STATIC s_aSkipDirs := { "tests", "example", "examples", "sample", "samples", ".svn", "%HB_ARCHITECTURE%" } +STATIC s_aSkipNames := { "MAIN" } // Init with method names you want to skip +STATIC s_aDirsProcessed := {} STATIC s_aMethodAsProcedure := {} STATIC s_aConditions := {} +#define capt_Desc 1 +#define capt_Cond 2 +#define capt_Repository 3 +#define Capture( desc, cond ) { desc, cond, {} } +STATIC s_aOutput // initialized within MAIN() + #define sw_BaseDir 1 #define sw_Target 2 #define sw_Verbose 3 @@ -97,29 +104,35 @@ STATIC s_aConditions := {} #define sw_ConditionalDepth 11 #define sw_MimicHBExtern 12 #define sw_ExcludeParams 13 -#define sw_SwitchesN 13 +#define sw_ExcludeContrib 14 +#define sw_SwitchesN 14 STATIC s_aSwitches[ sw_SwitchesN ] +#xcommand DEFAULT

TO => IF

== NIL ;

:= ; ENDIF + PROCEDURE MAIN( ... ) LOCAL aArgs := hb_AParams() LOCAL aDirs, i, nOutput, arg, cArgName + LOCAL ao, ar + LOCAL cDescription SET DATE FORMAT TO "yyyy-mm-dd" s_aSwitches[ sw_BaseDir ] := BASE_DIR s_aSwitches[ sw_Target ] := "hbextern.ch_" s_aSwitches[ sw_Verbose ] := 2 - s_aSwitches[ sw_Recursive ] := .F. + s_aSwitches[ sw_Recursive ] := .T. s_aSwitches[ sw_Case ] := 1 s_aSwitches[ sw_ExcludeDuplicates ] := .T. s_aSwitches[ sw_ExcludeEmptyFiles ] := .F. - s_aSwitches[ sw_ExcludeClasses ] := .T. + s_aSwitches[ sw_ExcludeClasses ] := .F. s_aSwitches[ sw_ExcludeClassMethods ] := .T. - s_aSwitches[ sw_ExcludeConditionals ] := .T. + s_aSwitches[ sw_ExcludeConditionals ] := .F. s_aSwitches[ sw_ConditionalDepth ] := 0 s_aSwitches[ sw_MimicHBExtern ] := .T. s_aSwitches[ sw_ExcludeParams ] := .T. + s_aSwitches[ sw_ExcludeContrib ] := .T. FOR EACH arg IN aArgs IF .NOT. Empty(arg) @@ -181,7 +194,7 @@ PROCEDURE MAIN( ... ) FOR i := 1 to Len(s_aSkipDirs) IF SubStr( s_aSkipDirs[i], 1, 1 ) == "%" - s_aSkipDirs[i] := GetEnv( SubStr( s_aSkipDirs[i], 2, Len( s_aSkipDirs[i] ) - 1 ) ) + s_aSkipDirs[i] := GetEnv( SubStr( s_aSkipDirs[i], 2, Len( s_aSkipDirs[i] ) - 2 ) ) ENDIF NEXT @@ -198,17 +211,55 @@ PROCEDURE MAIN( ... ) s_aSwitches[ sw_ExcludeClassMethods ] := .T. ENDIF +#define ca51 "/* CA-Cl*pper compatible standard functions */" +#define ca51int "/* CA-Cl*pper compatible internal functions */" +#define ca52und "/* CA-Cl*pper 5.2 compatible undocumented functions */" +#define ca53 "/* CA-Cl*pper 5.3 compatible functions */" +#define ca53X52 "/* CA-Cl*pper 5.3 compatible, CA-Cl*pper 5.2 undocumented, functions */" +#define harb "/* Harbour extensions */" +#define harbXcp "/* Harbour extensions, codepage support */" +#define harbXns "/* Harbour extensions violating extension namespace rules." + EOL + " See reasons in source. */" +#define dbgr "/* The debugger interface */" +#define rdd "/* RDD related symbols */" +#define rddSx "/* RDD SX related symbols */" +#define hiper "/* HiPer-SEEK compatible functions */" +#define cfts "/* CFTS compatible functions */" +#define i18n "/* i18n */" +#define cpsp "/* Codepage support */" +#define langsp "/* lang support */" +#define scalar "/* Scalar objects */" +#define xbasepp "/* Xbase++ compatible functions */" +#define dosunkn "/* DOS (?) */" +#define flagshp "/* FlagShip extension */" + + // store all entries that match the codeblock but build a sub-array of entries per conditionals + s_aOutput := { ; + Capture( ca51 , {|a,b,c,f| a,b,c,f, .T. } ), ; + Capture( ca51int, {|a,b,c,f| a,b,f, SubStr(c, 1, Len( "__") ) == "__" } ), ; + Capture( harb , {|a,b,c,f| a,b,f, SubStr(c, 1, Len( "HB_") ) == "HB_" } ), ; + Capture( dbgr , {|a,b,c,f| a,b,f, SubStr(c, 1, Len( "__DBG") ) == "__DBG" } ), ; + Capture( rdd , {|a,b,c,f| a,b,c, AT( PATH_SEPARATOR + "rdd" + PATH_SEPARATOR, f) > 0 } ), ; + Capture( rddSx , {|a,b,c,f| a,b, (SubStr(c, 1, 2) == "SX" .OR. SubStr(c, 1, 3) == "_SX" .OR. .F.) .AND. AT( PATH_SEPARATOR + "rdd" + PATH_SEPARATOR, f) > 0 } ), ; + Capture( hiper , {|a,b,c,f| a,b,f, SubStr(c, 1, Len( "HS_") ) == "HS_" } ), ; + Capture( cfts , {|a,b,c,f| a,b,f, SubStr(c, 1, Len( "CFTS") ) == "CFTS" } ), ; + Capture( i18n , {|a,b,c,f| a,b,f, SubStr(c, 1, Len( "HB_I18N") ) == "HB_I18N" } ), ; + Capture( cpsp , {|a,b,c,f| a,b,f, SubStr(c, 1, Len( "HB_CODEPAGE_") ) == "HB_CODEPAGE_" } ), ; + Capture( langsp , {|a,b,c,f| a,b,f, SubStr(c, 1, Len( "HB_LANG_") ) == "HB_LANG_" } ), ; + } + IF s_aSwitches[ sw_Recursive ] aDirs :={ ; s_aSwitches[ sw_BaseDir ] + "source", ; - s_aSwitches[ sw_BaseDir ] + "contrib", ; + IIf( s_aSwitches[ sw_ExcludeContrib ], NIL, s_aSwitches[ sw_BaseDir ] + "contrib" ), ; } ELSE aDirs :={ ; + s_aSwitches[ sw_BaseDir ] + "source" + PATH_SEPARATOR + "codepage", ; s_aSwitches[ sw_BaseDir ] + "source" + PATH_SEPARATOR + "debug", ; + s_aSwitches[ sw_BaseDir ] + "source" + PATH_SEPARATOR + "lang", ; s_aSwitches[ sw_BaseDir ] + "source" + PATH_SEPARATOR + "pp", ; s_aSwitches[ sw_BaseDir ] + "source" + PATH_SEPARATOR + "rdd", ; s_aSwitches[ sw_BaseDir ] + "source" + PATH_SEPARATOR + "rdd" + PATH_SEPARATOR + "dbfcdx", ; @@ -231,6 +282,8 @@ PROCEDURE MAIN( ... ) nOutput := FCreate( s_aSwitches[ sw_Target ] ) IF nOutput > 0 + CopyExistingTargetTo( nOutput ) + FWrite( nOutput, "// NOTE: Machine generated on: " + DTOC( DATE() ) + EOL + ; "// This output should be edited by hand after extraction." + EOL + EOL ) FWrite( nOutput, ; @@ -249,12 +302,19 @@ PROCEDURE MAIN( ... ) "*/" + EOL + ; EOL ; ) +#undef YesOrNo + + FWrite( nOutput, ; + "#ifndef HB_EXTERN_CH_" + EOL + ; + "#define HB_EXTERN_CH_" + EOL + ; + EOL ; + ) + FOR i := 1 TO LEN( aDirs ) IF .NOT. Empty(aDirs[i]) ProcessDir( nOutput, aDirs[i] ) ENDIF NEXT - FWrite( nOutput, EOL + "// " + Replicate( "-", 60 ) + EOL + EOL ) IF Len(s_aMethodAsProcedure) > 0 FWrite( nOutput, "/*" + EOL + "Class methods defined as 'procedure':" + EOL ) @@ -262,6 +322,38 @@ PROCEDURE MAIN( ... ) FWrite( nOutput, "*/" + EOL + EOL ) ENDIF + FOR EACH ao IN s_aOutput + IF ao != NIL + FWrite( nOutput, ao[ capt_Desc ] + EOL ) + IF LEn( ao[ capt_Repository ] ) == 0 + FWrite( nOutput, "/* empty */" + EOL ) + ELSE + FWrite( nOutput, EOL ) + FOR EACH ar in ao[ capt_Repository ] + IF ar[ capt_Cond ] != NIL .AND. Len( ar[ capt_Cond ] ) > 0 ; FWrite( nOutput, ar[ capt_Cond ] + EOL ); ENDIF + + ASort( ar[ capt_Repository ] ) + AEval( ar[ capt_Repository ], {|a| FWrite( nOutput, "EXTERNAL " + a + EOL ) } ) + + IF ar[ capt_Cond ] != NIL .AND. Len( ar[ capt_Cond ] ) > 0 + cDescription := "" + DO WHILE Len( ar[ capt_Cond ] ) > 0 + cDescription := "#endif /* " + Parse( @ar[ capt_Cond ], EOL ) + " */" + EOL + cDescription + ENDDO + FWrite( nOutput, cDescription ) + ENDIF + + FWrite( nOutput, EOL ) + NEXT + ENDIF + FWrite( nOutput, Stuff( ao[ capt_Desc ], 3, 0, "End of") + EOL + EOL ) + ENDIF + NEXT + + FWrite( nOutput, ; + "#endif /* HB_EXTERN_CH_ */" + EOL ; + ) + FClose( nOutput ) ENDIF @@ -270,6 +362,8 @@ PROCEDURE MAIN( ... ) RETURN STATIC PROCEDURE ShowHelp() +#define OnOrOff(b) IIf( b, "excluded", "included" ) + LOCAL aHelp := { ; "Syntax: ", ; " hbextern [options]", ; @@ -278,9 +372,9 @@ STATIC PROCEDURE ShowHelp() " -target= // target file, default is hbextern.ch_", ; " -recurse=[yes|no] // perform recursively, default is no", ; " -skipdirs= // configuration file of folders to bypass, default:", ; - {|| AEval( s_aSkipDirs, {|c| OutStd( IIf( Empty(c), "", " " + c ) + hb_osNewLine() ) } ) }, ; + {|| AEval( s_aSkipDirs, {|c| OutStd( IIf( Empty(c), "", " " + c ) + EOL ) } ) }, ; " -skipfiles= // configuration file of files to bypass, default:", ; - {|| AEval( s_aSkipFiles, {|c| OutStd( IIf( Empty(c), "", " " + c ) + hb_osNewLine() ) } ) }, ; + {|| AEval( s_aSkipFiles, {|c| OutStd( IIf( Empty(c), "", " " + c ) + EOL ) } ) }, ; " -verbose=[silent|minimum|maximum] // verbose operation, default is maximum", ; " -silent // synonym for verbose=silent", ; " -case=[upper|lower|unchanged] // output case, default is upper", ; @@ -288,29 +382,35 @@ STATIC PROCEDURE ShowHelp() " -exclude= // sets off", ; "switches:", ; " all // all switches are set", ; - " duplicates // default is on", ; - " empty-files // default is off", ; - " classes // default is off", ; - " class-methods // default is off", ; - " conditionals // default is off", ; - " params // default is off", ; + " duplicates // default is " + OnOrOff( s_aSwitches[ sw_ExcludeDuplicates ] ), ; + " empty-files // default is " + OnOrOff( s_aSwitches[ sw_ExcludeEmptyFiles ] ), ; + " classes // default is " + OnOrOff( s_aSwitches[ sw_ExcludeClasses ] ), ; + " class-methods // default is " + OnOrOff( s_aSwitches[ sw_ExcludeClassMethods ] ), ; + " conditionals // default is " + OnOrOff( s_aSwitches[ sw_ExcludeConditionals ] ), ; + " params // default is " + OnOrOff( s_aSwitches[ sw_ExcludeParams ] ), ; /* " ", */ ; } +#undef OnOrOff // using hbmk2 style - AEval( aHelp, {|x| IIf( ValType( x ) == "B", Eval( x ), OutStd( IIf( Empty(x), "", x ) + hb_osNewLine() ) ) } ) + AEval( aHelp, {|x| IIf( ValType( x ) == "B", Eval( x ), OutStd( IIf( Empty(x), "", x ) + EOL ) ) } ) RETURN STATIC PROCEDURE ProcessDir( nOutput, cDir ) LOCAL i, nLen, aFiles + // check for and prevent re-processing a folder + IF HB_AScan( s_aDirsProcessed, Lower( cDir ) ) > 0 + RETURN + ENDIF + AAdd( s_aDirsProcessed, Lower( cDir ) ) + IF s_aSwitches[ sw_Verbose ] > 0 ; ? cDir ; ENDIF - IF .NOT. s_aSwitches[ sw_ExcludeEmptyFiles ] - FWrite( nOutput, EOL + "// " + Replicate( "-", 60 ) + EOL ) - FWrite( nOutput, "// Files from: " + cDir + EOL + EOL ) - ENDIF + //~ IF .NOT. s_aSwitches[ sw_ExcludeEmptyFiles ] + //~ FWrite( nOutput, "// Files from: " + cDir + EOL + EOL ) + //~ ENDIF cDir += PATH_SEPARATOR @@ -318,12 +418,12 @@ STATIC PROCEDURE ProcessDir( nOutput, cDir ) IF ( nLen := LEN( aFiles ) ) > 0 // Sort C files before PRG files before folders; this mimics HBExtern ASort( aFiles,,, {|x,y| ; - IIf( x[ F_ATTR ] == "D", Chr(255), SubStr( x[ F_NAME ], At( ".", x[ F_NAME ] ) ) ) + x[ F_NAME ] < IIf( y[ F_ATTR ] == "D", Chr(255), SubStr( y[ F_NAME ], At( ".", y[ F_NAME ] ) ) ) + y[ F_NAME ] ; + IIf( x[ F_ATTR ] == "D", Chr(255), SubStr( x[ F_NAME ], 1 + HB_RAt( ".", x[ F_NAME ] ) ) ) + x[ F_NAME ] < IIf( y[ F_ATTR ] == "D", Chr(255), SubStr( y[ F_NAME ], 1 + HB_RAt( ".", y[ F_NAME ] ) ) ) + y[ F_NAME ] ; } ) FOR i := 1 TO nLen IF aFiles[ i ][F_ATTR ] == "D" IF s_aSwitches[ sw_Recursive ] .AND. ; - AScan( s_aSkipDirs, {|d| Lower(d) == Lower( aFiles[ i ][ F_NAME ] ) } ) == 0 + HB_AScan( s_aSkipDirs, {|d| Lower(d) == Lower( aFiles[ i ][ F_NAME ] ) } ) == 0 ProcessDir( nOutput, cDir + aFiles[ i ][ F_NAME ] ) ENDIF ELSEIF Upper( SubStr( aFiles[ i ][ F_NAME ], -4 ) ) == ".PRG" @@ -340,8 +440,7 @@ STATIC FUNCTION FileToArray( cFile ) LOCAL nH LOCAL aResult := {} - nH := FOpen( cFile ) - IF nH > 0 + IF ( nH := FOpen( cFile ) ) > 0 FileEval( nH, 255, {|c| AAdd( aResult, c ) } ) FClose( nH ) ELSE @@ -356,7 +455,7 @@ STATIC PROCEDURE ProcessFile( nOutput, cFile, lPRG ) LOCAL cHeader // Skip known files which does not contain any real public function - IF AScan( s_aSkipFiles, {|c| lower(c) $ lower( cFile ) } ) > 0 + IF HB_AScan( s_aSkipFiles, {|c| lower(c) $ lower( cFile ) } ) > 0 RETURN ENDIF @@ -365,7 +464,7 @@ STATIC PROCEDURE ProcessFile( nOutput, cFile, lPRG ) cHeader := "//" + EOL + "// symbols from file: " + cFile + EOL + "//" + EOL IF .NOT. s_aSwitches[ sw_ExcludeEmptyFiles ] - FWrite( nOutput, cHeader ) + //~ FWrite( nOutput, cHeader ) bOutputHeader := .F. ELSE bOutputHeader := .T. @@ -375,7 +474,7 @@ STATIC PROCEDURE ProcessFile( nOutput, cFile, lPRG ) IF nH > 0 FileEval( nH, 255, {|c| ProcessLine( nOutput, cFile, c, lPRG, @bOutputHeader, @cHeader ) } ) FClose( nH ) - FWrite( nOutput, Replicate( "#endif" + EOL, s_aSwitches[ sw_ConditionalDepth ] ) ) + //~ FWrite( nOutput, Replicate( "#endif" + EOL, s_aSwitches[ sw_ConditionalDepth ] ) ) s_aSwitches[ sw_ConditionalDepth ] := 0 ELSE IF s_aSwitches[ sw_Verbose ] > 0 ; ? "Could not process [" + cFile + "], error " + hb_ntos(nH) ; ENDIF @@ -450,45 +549,57 @@ STATIC s_cMethodType, s_lVisible, s_FullLine := "" cLine := s_FullLine + cLine s_FullLine := "" - IF lPRG // PRG source file (FUNC, PROC, CLASS) - - IF .NOT. s_aSwitches[ sw_ExcludeConditionals ] .AND. SubStr( cLine, 1, 1 ) == "#" - IF SubStr( cLine, 1, 2 ) == "# " - cLine := "#" + LTrim( SubStr( cLine, 2 ) ) - ENDIF - - IF .F. -/* - ELSEIF Lower( SubStr( cLine, 1, Len( "#include" ) ) ) == "#include" - ELSEIF Lower( SubStr( cLine, 1, Len( "#define" ) ) ) == "#define" - ELSEIF Lower( SubStr( cLine, 1, Len( "#undef" ) ) ) == "#undef" - ELSEIF Lower( SubStr( cLine, 1, Len( "#pragma " ) ) ) == "#pragma " - ELSEIF Lower( SubStr( cLine, 1, Len( "#command" ) ) ) == "#command" - ELSEIF Lower( SubStr( cLine, 1, Len( "#xcommand" ) ) ) == "#xcommand" - ELSEIF Lower( SubStr( cLine, 1, Len( "#translate" ) ) ) == "#translate" - ELSEIF Lower( SubStr( cLine, 1, Len( "#xtrans" ) ) ) == "#xtrans" - ELSEIF Lower( SubStr( cLine, 1, Len( "#error " ) ) ) == "#error " -*/ - ELSEIF Lower( SubStr( cLine, 1, Len( "#if" ) ) ) == "#if" - AAdd( s_aConditions, cLine ) - ELSEIF Lower( SubStr( cLine, 1, Len( "#elif" ) ) ) == "#elif" - s_aConditions[ Len( s_aConditions ) ] := cLine - ELSEIF Lower( SubStr( cLine, 1, Len( "#else" ) ) ) == "#else" - IF s_aSwitches[ sw_ConditionalDepth ] > 0 - FWrite( nOutput, "#else" + EOL ) - ENDIF - s_aConditions[ Len( s_aConditions ) ] := cLine - ELSEIF Lower( SubStr( cLine, 1, Len( "#endif" ) ) ) == "#endif" - IF s_aSwitches[ sw_ConditionalDepth ] > 0 - FWrite( nOutput, "#endif" + EOL ) - s_aSwitches[ sw_ConditionalDepth ]-- - ENDIF - ASize( s_aConditions, Len( s_aConditions ) - 1 ) - //~ ELSE - //~ ? cLine - ENDIF + IF .NOT. s_aSwitches[ sw_ExcludeConditionals ] .AND. SubStr( cLine, 1, 1 ) == "#" + IF SubStr( cLine, 1, 2 ) == "# " + cLine := "#" + LTrim( SubStr( cLine, 2 ) ) ENDIF + IF .F. +/* + ELSEIF Lower( SubStr( cLine, 1, Len( "#include" ) ) ) == "#include" + ELSEIF Lower( SubStr( cLine, 1, Len( "#define" ) ) ) == "#define" + ELSEIF Lower( SubStr( cLine, 1, Len( "#undef" ) ) ) == "#undef" + ELSEIF Lower( SubStr( cLine, 1, Len( "#pragma " ) ) ) == "#pragma " + ELSEIF Lower( SubStr( cLine, 1, Len( "#command" ) ) ) == "#command" + ELSEIF Lower( SubStr( cLine, 1, Len( "#xcommand" ) ) ) == "#xcommand" + ELSEIF Lower( SubStr( cLine, 1, Len( "#translate" ) ) ) == "#translate" + ELSEIF Lower( SubStr( cLine, 1, Len( "#xtrans" ) ) ) == "#xtrans" + ELSEIF Lower( SubStr( cLine, 1, Len( "#error " ) ) ) == "#error " +*/ + ELSEIF Lower( SubStr( cLine, 1, Len( "#if" ) ) ) == "#if" + AAdd( s_aConditions, cLine ) + ELSEIF Lower( SubStr( cLine, 1, Len( "#elif" ) ) ) == "#elif" + s_aConditions[ Len( s_aConditions ) ] := cLine + ELSEIF Lower( SubStr( cLine, 1, Len( "#else" ) ) ) == "#else" + IF s_aSwitches[ sw_ConditionalDepth ] > 0 + //~ FWrite( nOutput, "#else" + EOL ) + + //~ s_aConditions[ Len( s_aConditions ) ] := cLine + DO CASE + CASE SubStr( ATail( s_aConditions ), 1, Len( "#if " ) ) == "#if " + s_aConditions[ Len( s_aConditions ) ] := "#if !(" + SubStr( ATail( s_aConditions ), Len( "#if " ) + 1 ) + ")" + CASE SubStr( ATail( s_aConditions ), 1, Len( "#ifdef " ) ) == "#ifdef " + s_aConditions[ Len( s_aConditions ) ] := "#ifndef " + SubStr( ATail( s_aConditions ), Len( "#ifdef " ) + 1 ) + CASE SubStr( ATail( s_aConditions ), 1, Len( "#ifndef " ) ) == "#ifndef " + s_aConditions[ Len( s_aConditions ) ] := "#ifdef " + SubStr( ATail( s_aConditions ), Len( "#ifndef " ) + 1 ) + OTHERWISE + // TODO: print a more useful error message + ? "Error:", cLine, ATail(s_aConditions) + ENDCASE + ENDIF + ELSEIF Lower( SubStr( cLine, 1, Len( "#endif" ) ) ) == "#endif" + IF s_aSwitches[ sw_ConditionalDepth ] > 0 + //~ FWrite( nOutput, "#endif" + EOL ) + s_aSwitches[ sw_ConditionalDepth ]-- + ENDIF + ASize( s_aConditions, Len( s_aConditions ) - 1 ) + //~ ELSE + //~ ? cLine + ENDIF + ENDIF + + IF lPRG // PRG source file (FUNC, PROC, CLASS) + IF Upper( SubStr( cLine, 1, Len( "FUNC " ) ) ) == "FUNC " .OR. ; Upper( SubStr( cLine, 1, Len( "PROC " ) ) ) == "PROC " .OR. ; Upper( SubStr( cLine, 1, Len( "FUNCTION " ) ) ) == "FUNCTION " .OR. ; @@ -510,9 +621,17 @@ STATIC s_cMethodType, s_lVisible, s_FullLine := "" s_lVisible := .T. // TODO: what is the default visibility of methods OTHERWISE s_cMethodType = Upper( SubStr( cLine, 1, 4 ) ) - END + ENDCASE aUnits := Split(RemoveComments(cLine), " ") + + IF s_cMethodType == "CLASS" + // TOFIX: dependant upon there being no double spaces in the source line + IF Len(aUnits) > 1 .AND. Upper( aUnits[ Len( aUnits ) - 1 ] ) == "FUNCTION" + cLine := s_cMethodType + " " + aUnits[ Len( aUnits ) ] + ENDIF + ENDIF + IF Upper( SubStr( cLine, 1, Len( "PROC" ) ) ) == "PROC" .AND. Len(aUnits) > 1 .AND. Upper( aUnits[ Len( aUnits ) - 1 ] ) == "CLASS" AAdd(s_aMethodAsProcedure, { cFile, cLine } ) ELSEIF ( nPos := AT( " ", cLine ) ) > 4 @@ -524,7 +643,7 @@ STATIC s_cMethodType, s_lVisible, s_FullLine := "" EXIT ENDIF NEXT - WriteSymbol( nOutput, SubStr( cLine, 1, nPos ), s_cMethodType + " " + RemoveComments( SubStr( cLine, nPos + 1 ) ), @bOutputHeader, @cHeader ) + WriteSymbol( nOutput, cFile, SubStr( cLine, 1, nPos ), s_cMethodType + " " + RemoveComments( SubStr( cLine, nPos + 1 ) ), @bOutputHeader, @cHeader ) ENDIF ELSEIF s_cMethodType == "CLASS" cLine := RemoveComments(cLine) @@ -542,7 +661,7 @@ STATIC s_cMethodType, s_lVisible, s_FullLine := "" cLine := Parse( @cLine, " INIT " ) cLine := Parse( @cLine, " INLINE " ) cLine := Trim( cLine ) - WriteSymbol( nOutput, " " + cLine, ""/*s_cMethodType*/, @bOutputHeader, @cHeader ) // SubStr( cLine, 1, nPos ), s_cMethodType ) + WriteSymbol( nOutput, cFile, " " + cLine, ""/*s_cMethodType*/, @bOutputHeader, @cHeader ) // SubStr( cLine, 1, nPos ), s_cMethodType ) ENDIF ELSEIF Upper( SubStr( cLine, 1, Len( "ENDCLASS" ) ) ) == "ENDCLASS" s_cMethodType := "" @@ -556,10 +675,22 @@ STATIC s_cMethodType, s_lVisible, s_FullLine := "" ELSE // C source file (HB_FUNC) #ENDIF - IF SubStr( cLine, 1, 8 ) == "HB_FUNC(" - cLine := SubStr( cLine, 9 ) + IF ; + SubStr( cLine, 1, Len( "HB_FUNC(" ) ) == "HB_FUNC(" .OR. ; + SubStr( cLine, 1, Len( "HB_CODEPAGE_INIT(" ) ) == "HB_CODEPAGE_INIT(" .OR. ; + SubStr( cLine, 1, Len( "HB_LANG_ANNOUNCE(" ) ) == "HB_LANG_ANNOUNCE(" .OR. ; + .F. + + DO CASE + CASE SubStr( cLine, 1, Len( "HB_FUNC(" ) ) == "HB_FUNC(" ; s_cMethodType := "" + CASE SubStr( cLine, 1, Len( "HB_CODEPAGE_INIT(" ) ) == "HB_CODEPAGE_INIT(" ; s_cMethodType := "HB_CODEPAGE_" + CASE SubStr( cLine, 1, Len( "HB_LANG_ANNOUNCE(" ) ) == "HB_LANG_ANNOUNCE(" ; s_cMethodType := "HB_LANG_" + OTHERWISE + END + + Parse( @cLine, "(" ) IF ( nPos := AT( ")", cLine ) ) > 0 - WriteSymbol( nOutput, AllTrim( SubStr( cLine, 1, nPos - 1 ) ), "C function", @bOutputHeader, @cHeader ) + WriteSymbol( nOutput, cFile, s_cMethodType + AllTrim( SubStr( cLine, 1, nPos - 1 ) ), "C function", @bOutputHeader, @cHeader ) ENDIF ENDIF @@ -575,11 +706,43 @@ STATIC PROCEDURE FileEval( nHandle, nMaxLine, bBlock ) FSeek( nHandle, 0 ) DO WHILE FReadLn( nHandle, @cBuffer, nMaxLine ) - Eval( bBlock, cBuffer ) + IF SubStr( LTrim( cBuffer ), 1, 2 ) == "/*" + FSeek( nHandle, -( Len( cBuffer ) - 2 ), FS_RELATIVE ) + IF .NOT. FReadUntil( nHandle, "*/" ) + EXIT + ENDIF + ELSE + Eval( bBlock, cBuffer ) + ENDIF ENDDO RETURN +STATIC FUNCTION FReadUntil( nHandle, cMatch, cResult ) + LOCAL cBuffer, nSavePos, nIdxMatch, nNumRead + + DEFAULT cResult TO "" + + DO WHILE nNumRead != 0 + nSavePos := FSeek( nHandle, 0, FS_RELATIVE ) + cBuffer := Space( 255 ) + IF ( nNumRead := FRead( nHandle, @cBuffer, Len( cBuffer ) ) ) == 0 + RETURN .F. + ENDIF + cBuffer := SubStr( cBuffer, 1, nNumRead ) + + IF ( nIdxMatch := At( cMatch, cBuffer ) ) > 0 + cResult += SubStr( cBuffer, 1, nIdxMatch + Len( cMatch ) - 1 ) + FSeek( nHandle, nSavePos + nIdxMatch + Len( cMatch ) - 1, FS_SET ) + RETURN nNumRead != 0 + ELSE + cResult += SubStr( cBuffer, 1, nNumRead - Len( cMatch ) ) + FSeek( nHandle, -Len( cMatch ), FS_RELATIVE ) + ENDIF + ENDDO + + RETURN nNumRead != 0 + STATIC FUNCTION FReadLn( nHandle, cBuffer, nMaxLine ) STATIC s_aEOL := { chr(13) + chr(10), chr(10), chr(13) } LOCAL cLine, nSavePos, nEol, nNumRead, nLenEol, idx @@ -601,24 +764,31 @@ STATIC s_aEOL := { chr(13) + chr(10), chr(10), chr(13) } NEXT IF nEol == 0 - cBuffer := cLine + cBuffer := cLine ELSE - cBuffer := SubStr( cLine, 1, nEol - 1 ) - FSeek( nHandle, nSavePos + nEol + nLenEol, FS_SET ) + cBuffer := SubStr( cLine, 1, nEol - 1 ) + FSeek( nHandle, nSavePos + nEol + nLenEol, FS_SET ) ENDIF RETURN nNumRead != 0 -STATIC PROCEDURE WriteSymbol( nOutput, cLine, cMethodType, bOutputHeader, cHeader ) +STATIC PROCEDURE WriteSymbol( nOutput, cFile, cLine, cMethodType, bOutputHeader, cHeader ) + LOCAL idxOutput, idxRepository + LOCAL cConditions + + DEFAULT nOutput TO 0 + DEFAULT cHeader TO "" + IF Len( cLine ) > 0 IF s_aSwitches[ sw_Case ] == 1 cLine := Upper( cLine ) ELSEIF s_aSwitches[ sw_Case ] == 2 cLine := Lower( cLine ) ENDIF - IF AScan( s_aSkipNames , {|c| Upper(c) == Upper(cLine) } ) == 0 + + IF HB_AScan( s_aSkipNames , {|c| Upper(c) == Upper(cLine) } ) == 0 IF bOutputHeader - FWrite( nOutput, cHeader ) + //~ FWrite( nOutput, cHeader ) bOutputHeader := .F. ENDIF @@ -626,10 +796,8 @@ STATIC PROCEDURE WriteSymbol( nOutput, cLine, cMethodType, bOutputHeader, cHeade AAdd( s_aSkipNames, cLine ) ENDIF - IF cMethodType <> "C function" - IF s_aSwitches[ sw_ConditionalDepth ] == 0 - AEval( s_aConditions, {|c| s_aSwitches[ sw_ConditionalDepth ]++, FWrite( nOutput, c + EOL ) } ) - ENDIF + IF s_aSwitches[ sw_ConditionalDepth ] == 0 + AEval( s_aConditions, {|/* c */| s_aSwitches[ sw_ConditionalDepth ]++/* , FWrite( nOutput, c + EOL ) */ } ) ENDIF IF s_aSwitches[ sw_MimicHBExtern ].OR. Empty(cMethodType) .OR. s_aSwitches[ sw_ExcludeClassMethods ] @@ -638,8 +806,38 @@ STATIC PROCEDURE WriteSymbol( nOutput, cLine, cMethodType, bOutputHeader, cHeade cMethodType = " // " + cMethodType ENDIF - FWrite( nOutput, "EXTERNAL " + cLine + cMethodType + EOL ) + cConditions := "" + AEval( s_aConditions, {|c| cConditions += c + EOL } ) + IF Len( cConditions ) > Len( EOL ) ; cConditions := SubStr( cConditions, 1, Len( cConditions ) - Len( EOL ) ) ; ENDIF + + // the first entry has a hard-coded TRUE value so one will always be found + idxOutput := HB_RAScan( s_aOutput, {|ao| ; + ao != NIL .AND. ; + Eval( ao[ capt_Cond ], ao, cConditions, cLine, cFile ) ; + } ) + idxRepository := HB_AScan( s_aOutput[ idxOutput ][ capt_Repository ], {|ar| ; + ar[ capt_Cond ] == cConditions ; + } ) + IF idxRepository == 0 + AAdd( s_aOutput[ idxOutput ][ capt_Repository ], Capture( NIL, cConditions ) ) + idxRepository := Len( s_aOutput[ idxOutput ][ capt_Repository ] ) + ENDIF + AAdd( s_aOutput[ idxOutput ][ capt_Repository ][ idxRepository ][ capt_Repository ], cLine /* + cHeader */ ) + + //~ FWrite( nOutput, "EXTERNAL " + cLine + cMethodType + EOL ) ENDIF ENDIF RETURN + +STATIC PROCEDURE CopyExistingTargetTo( nOutput ) + LOCAL nInput + LOCAL cBuffer1, cBuffer2 + + IF ( nInput := FOpen( s_aSwitches[ sw_BaseDir ] + PATH_SEPARATOR + "include" + PATH_SEPARATOR + "hbextern.ch" ) ) > 0 + // assume there are two comment blocks seperated by a blank line (svn header and copyright) + IF FReadUntil( nInput, "*/", @cBuffer1 ) .AND. FReadUntil( nInput, "*/", @cBuffer2 ) + FWrite( nOutput, cBuffer1 + cBuffer2 + EOL + EOL ) + ENDIF + FClose( nInput ) + ENDIF