How I can check validity of a macro ?

PROC MAIN()

    nResult   := NIL
    nDivident := 1
    nDivisor  := 0
    cMacro    := " nResult := nDivident / nDivisor "  
    QOutResult( nDivident, nDivisor, cMacro ) // 1  0  UE macro is inValid

    nDivisor  := 2
    QOutResult( nDivident, nDivisor, cMacro ) // 1  2  N  Result is :  0.50

    cMacro    := "AT( 'OK', MyUDF() ) > 0"              
    QOutResult( 'AT( OK', 'MyUDF()', cMacro ) // AT( OK ... U macro is inValid

    cMacro    :=  "{ 1, 2 }[ 2 ]"                       
    QOutResult( '{ 1, 2 }', '[2]', cMacro ) // { 1, 2 } [2]   N Result is : 2

    cMacro    :=  "{ 1, 2 }[ 5 ]"  
    QOutResult( '{ 1, 2 }', '[5]', cMacro ) // { 1, 2 } [5] UE macro is inValid

    lCond := 0
    cMacro    :=  "if( lCond, 'true', MyUDF() )"
    QOutResult( lCond, '', cMacro )           // 0        U macro is inValid   
    ?
    WAIT

RETU // Main()

*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.

PROC QOutResult( xVal1, xVal2, cMacro )

	LOCAL cType := TYPE( cMacro )

	? PAD( xVal1, 10 ), PAD( xVal2, 10 ),  PAD( cType, 3 )

    IF ( cType # "U") 
       ?? "Result is :", &cMacro
    ELSE
       ?? "macro is inValid"
    ENDIF

RETU // QOutResult()

*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._

See Also:

& (macro evaluation unary) Operator 

Macro Compiler

HB_SetMacro()

ValType()

TYPE()

C5_TYPE()

Mini Search Machine (2014)

Mini Search Machine ( MSM ) is a mini search utility for HMG users.

Purposes of this program is denote extreme power and flexibility of HMG and some goodies of command line and batch processing.

And of course (as always) being useful to HMG community by giving a humble example.

Thanks to builder and all kind of supporter and follower of HMG

And special thanks to Sr. P.C. Toledo for inspiration, hint for internet search and especially wonderful Clipper Online forum.

MSM_01

MSM_02

Notes :

– Please check folder definitions in MSM.ch depending on your configuration
– When output flow become annoyingly long, you can
– use “Wait Pages” option before starting
– use “Pause” key of keyboard and then any key to continue
– cut flow by pressing Ctrl-C or Ctrl-Break
– simply use X button
– I couldn’t implement “F:file” switch of FINDSTR; any idea ?

Happy HMG’ing 😀

Download :

Source files

Executable

 

How I can find empty fields in my table ?

This sample test program scan any table records for empty fields in any type ,
and reports number of record(s) included empty field(s) with number of FIRST empty field.

#include <hmg.ch>

PROC MAIN

   SET( _SET_EOF, .F. )

   USE TEST

   nFldCount := FCOU()
   cTestFNam := "empties.txt"
   nEmptyRec := 0

   SET ALTERNATE TO (cTestFNam)
   SET ALTERNATE ON

   WHIL ! EOF()
      FOR nFld := 1 TO nFldCount
         IF EMPTY( FIELDGET( nFld ) )
            ? RECN(), nFld
            ++nEmptyRec
            EXIT
         ENDI
      NEXT
      SKIP
   ENDD

   SET ALTE OFF
   SET ALTE TO
   MsgBox( LTRIM( STR( RECC() ) ) + " records with " +; 
           LTRIM( STR( nFldCount ) ) + " field(s) scanned ;" +;
           CRLF + ;
           LTRIM( STR( nEmptyRec ) ) + ;
           " records found with empty field." )

   EXECUTE FILE "NOTEPAD.EXE" PARAMETERS cTestFNam
RETU

Extract non alphanumerics

* How I can remove all non alpha-numeric characters from a string

#include <hmg.ch>
 
/*
   Remove all non alpha-numeric characters from a string
*/

PROC MAIN

   cOriginal := "=<abc_-.#@123>#+-.,"
   cCleaned  := RemNAN( cOriginal )
   
   MsgBox( "Original : " + cOriginal + STR( LEN( cOriginal ), 3 ) +;
            CRLF + ; 
           "Cleaned  : " + cCleaned  + STR( LEN( cCleaned ), 3 ) )  
RETU

*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

FUNC RemNAN( cString )

   LOCAL cRVal  := "",;
         c1Char := ""
       
   FOR EACH c1Char IN cString
      cRVal += IF( ISALPHA( c1Char ) .OR. ISDIGIT( c1Char ), ;
               c1Char, "" )         
   NEXT   
      
RETU cRVal

*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

remNAN

What are basic data types ?

Types of FIELD variables are defined in STRUCTURE of tables (.dbf files).

For other type (memory) variables, Clipper isn’t a “strong typing” language. Programmers not obliged to define variables with type before referenced (used); variables are typed “on the fly” that is by assigning value.

Notes :

  • “M” (memo) type is usable only in .dbf files, there isn’t “M” type variable. In terms of operation, “M” data is similar  to character type.
  • Harbour has 6 scalar types : Nil, String, Date, Logical, Number, Pointer, and 4 complex types: Array, Object, CodeBlock, and Hash. Types cited here are BASIC type: String, Number, Logical and Date.
  • For more info about data types please refer here.
  • Harbour supports also “extended” field types; see here.
  • There is also NIL type that has only one allowable value: NIL. NIL is not “undefined”, simply “nothing”.
  • This program also use “ALTERNATE” writing feature for display program output. This is handy for especially debugging and logging purposes.

/*

A little test program to explore basic data types in Clipper.

*/   

#include <hmg.ch>

PROC MAIN

   * Some global settings
   SET( _SET_EOF, .F. )                // Don't put EOF marker to end of files built
   SET CENTURY ON                      // Display Century portion of dates type data
   
   * Set test file name
   cTestFNam := "DataTypes.txt"        // Name of test file
   
   * Set and open alternate file
   SET ALTERNATE TO (cTestFNam)        // Redirect screen (console) output 
                                       // (results of ? commands) to that file  
   SET ALTERNATE ON                    // Open alternate writing  
   
   * Assign values to variables
   cCharVar := "This is a character data"   // Assign astring value to this variable 
   nNumrVar := 123.456                // Assign this numeric value to this variable 
   lLogiVar := .T.                    // Assign this logical value to this variable    
   dDateVar := DATE()                 // Assign this date type value (date of day) 
                                      // to this variable  
   
   * Write variable names and value
   ? "cCharVar :", TYPE( "cCharVar" ), cCharVar
   ? "nNumrVar :", TYPE( "nNumrVar" ), nNumrVar
   ? "lLogiVar :", TYPE( "lLogiVar" ), lLogiVar
   ? "dDateVar :", TYPE( "dDateVar" ), dDateVar
   
   * Close alternate writing and file
   SET ALTE OFF                             // Close alternate writing 
   SET ALTE TO                              // Close alternate file 
   
   * Run Notepad of Windows and send to it my test file
   EXECUTE FILE "NOTEPAD.EXE" PARAMETERS cTestFNam 

RETU
   
*-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.