macro_file METOOLS;

#include WINDOWS.SH
#include METOOLS.SH
#include MEW.SH

#ifdef _DEBUG_
	#include DBUG.SH
  #include MSGLOG.SH
#endif

void WriteIt( ) trans2
/******************************************************************************
															 Multi-Edit Macro
															 25-Sep-95  12:16

  Function: Runs the passed macro and writes the string in Return_Str returned
            by the macro to the current cursor position.

  Entry   : Macro command line

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/
{
	Rm( MParm_Str );
	Text( Return_Str );

}  // WriteIt

void SetDefTransTbls( ) trans2
/******************************************************************************
															 Multi-Edit Macro
															 18-Sep-95  17:40

  Function: Sets the default tables global variables used by the Translate
            macro to convert alpha characters from one case to the other.

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/
{
 	g_DefTransInTbl  = "'\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
	g_DefTransOutTbl = "\"'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

}  // SetDefTransTbls

str Translate(
			str String 	 = Parse_Str( "/S=", MParm_Str ),
			str OutTable = Parse_Str( "/O=", MParm_Str ),
			str InTable	 = Parse_Str( "/I=", MParm_Str ),
			...
) trans2
/******************************************************************************
															 Multi-Edit Macro
															 18-Sep-95  17:13

  Function: Returns a string with characters in String that are in InTable
            translated to the corresponding character in OutTable (OutTable is
            padded with PadChar if needed).  If neither translate table is
            specified, String is translated to opposite case as setup by the
            SetDefTransTbls fuction.

  Entry   : str String      - The string                                ( /S= )
            str OutTable    - Output table                              ( /O= )
            str InTable     - Input table                               ( /I= )
            [ str PadChar ] - Optional pad character (defaults to blank)

  Exit    : str             - Translated string

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/
{
	int Jx;
	int Jy;
	int StrLen = Svl( String );

	str PadChar = Get_Param_Str( 1 );
	str Result;

	char CurChar;

	if ( Svl( PadChar ) > 1 ) {
		PadChar = Str_Char( PadChar, 1 );
	}
	else if ( Svl( PadChar ) == 0 ) {
		PadChar = " ";
	}
	if ( ( Svl( InTable ) == 0 ) && ( Svl( OutTable ) == 0 ) ) {
		if ( Length( g_DefTransInTbl ) == 0 ) {
			SetDefTransTbls( );
		}
		InTable = g_DefTransInTbl;
		OutTable = g_DefTransOutTbl;
	}
	else if ( Svl( InTable ) == 0 ) {
		for ( Jx = 0; Jx < 0x100; ++Jx ) {
			InTable = Char( Jx );
		}
	}
	Pad_Str( OutTable, Svl( InTable ), PadChar );
	for ( Jx = 1; Jx <= StrLen ; ++Jx ) {
		CurChar = Str_Char( String, Jx );
		Jy = XPos( CurChar, InTable, 1 );
		if ( Jy ) {
			Result += Str_Char( OutTable, Jy );
		}
		else {
			Result += CurChar;
		}
	}
	return ( Result );

}  // Translate

int StrAbbrev( str FullStr, str TestStr, ... ) trans2
/******************************************************************************
															 Multi-Edit Macro
															 18-Sep-95  22:50

  Function: Return True when TestStr is equal to the leading characters of
            FullStr and the length of TestStr is at least Len long, otherwise
						return False.

  Entry   : str FullStr		- Full string to check the abbreviated string against
						str TestStr 	- The abbreviated string
						[ int Len ] 	- Optional length, default length of TestStr

  Exit    :	int
							True      	- Match found
							False     	- No match

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/
{
	int Len = Get_Param_Int( 1 );
	int Result = False;

	if ( Len < 1 ) {
		Len = Svl( TestStr );
	}
	if ( Len <= Svl( TestStr ) ) {
		Result = ( TestStr == Copy( FullStr, 1, Len ) );
	}
	return ( Result );

}  // StrAbbrev

str StrCenter( str String, int Len, ... ) trans2
/******************************************************************************
															 Multi-Edit Macro
															 18-Sep-95  23:21

  Function: Returns a string of length Len with String center in it, optionally
            padded with PadChar (defaults to blank) or truncated as needed.
            Odd number of truncation is applied to the right side.

  Entry   : str String      - String to center
            int Len         - Length of return string
            [ str PadChar ] - Optional pad character

  Exit    : str             - String of length Len with String center in it.

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/
{
	str Result;

	if ( Len > 0 ) {

		str PadChar = Get_Param_Str( 1 );

		int Jx;

		if ( Svl( PadChar ) == 0 ) {
			PadChar = " ";
		}
		Jx = Svl( String );
		if ( Jx > Len ) {
			Jx = ( Jx - Len ) / 2;
			Result = Copy( String, Jx + 1, Len );
		}
		else {
			Jx = ( Len - Jx ) / 2;
			Pad_Str( Result, Jx, PadChar );
			Result += String;
			Pad_Str( Result, Len, PadChar );
		}
	}
	return ( Result );

}  // StrCenter

str StrLeft( str String, int Len, ... ) trans2
/******************************************************************************
															 Multi-Edit Macro
															 18-Sep-95  23:56

  Function: Returns a string of length Len containing the left-most Len
            characters of String, padded with Pad or truncated on the right as
            needed.  PadChar defaults to blank.

  Entry   : str String      - The string
            int Len         - The length of the returned string.
            [ str PadChar ] - Optional pad character (defaults to blank)

  Exit    : str             - The Len left most chars of String.

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/
{
	str Result;

	if ( Len > 0 ) {

		str PadChar = Get_Param_Str( 1 );

		int Jx;

		if ( Svl( PadChar ) == 0 ) {
			PadChar = " ";
		}
		Jx = Svl( String );
		Result = Copy( String, 1, Len );
		if ( Jx < Len ) {
			Pad_Str( Result, Len, PadChar );
		}
	}
	return ( Result );

}  // StrLeft

str StrRight( str String, int Len, ... ) trans2
/******************************************************************************
															 Multi-Edit Macro
															 18-Sep-95  23:56

  Function: Returns a string of length Len containing the right-most Len
            characters of String, padded with Pad or truncated on the left as
            needed.

  Entry   : str String      - The string
            int Len         - The length of the returned string
            [ str PadChar ] - Optional pad character (defaults to blank)

  Exit    : str             - The right-most Len characters of String

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/
{
	str Result;

	if ( Len > 0 ) {

		str PadChar = Get_Param_Str( 1 );

		int Jx;

		if ( Svl( PadChar ) == 0 ) {
			PadChar = " ";
		}
		Jx = Svl( String );
		if ( Jx < Len ) {
			Pad_Str( Result, Len - Jx, PadChar );
			Result += Copy( String, 1, Jx );
		}
		else {
			Jx = Len - Jx;
			Result = Copy( String, Jx + 1, Len );
		}
	}
	return ( Result );

}  // StrRight

str StrCopies(
			str String = Parse_Str( "/S=", MParm_Str ),
			int Cnt = Parse_Int( "/C=", MParm_Str )
)
/******************************************************************************
															 Multi-Edit Macro
															 30-Jun-95  16:48

  Function: Returns Cnt concatenated copies of String.

  Entry   : str String    - The string
            int Cnt       - Number of copies to concatenate
  Exit    : str           - The concatenated string

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/
{
	str TStr;

	while ( Cnt-- ) {
		TStr += String;
	}
	return ( Return_Str = TStr );

}  // StrCopies

str TranslateCmdline( str Cmdline[ MAX_LINE_LENGTH ], str FName[ 1024 ] ) trans2
/*******************************************************************************
Description:  Translates cmdline so that any occurances of
							<FILE>, <NAME>, <EXT>, <PATH>, <ME_PATH>, <USER_PATH>, <MAC_PATH>
							 are expanded out.

							Also, <%str> is now expanded out to whatever the environment
							variable "str" is.
							AND, <~str> is now expanded out to the value of
							Global_Str( str ).

							fname is the file name to be used.

							(C) Copyright 1991-96 by American Cybernetics, Inc.
*******************************************************************************/
{
	if ( XPos( "<", CmdLine, 1 ) ) {

		int Jx;
		int Jy;
		int UseLFN = False;

		str Alias;
    str TStr[ MAX_LINE_LENGTH ];
    str	sTime[ 2 ];
    str	Time_Str[ 12 ];
    str	FTime_Str[ 12 ];
    str	FDate_Str[ 12 ];

//#ifdef _Debug_
//	DebugLog( 1, "tcl-Before", "F=%s| %s", FName, Cmdline );
//#endif
		// Use short file names by default
		FName = GetShortName( FName );
  	if ( XPos( "<CTIME>", Caps( Cmdline ), 1 ) ) {
			// Only do this stuff if this metacommand exists
    	GetProfileString( "intl", "sTime", ":", sTime, 2 );

			// Setup Current time string
    	Time_Str  = Str_Del( Time, 6, 3 );
    	if ( XPos( sTime, Time_Str, 1 ) == 2 ) {
      	Time_Str = Str_Del( Time, 5, 3 );
			}
  	}
  	if (XPos( "<FTIME>", Caps( Cmdline ), 1 ) ||
        XPos( "<FDATE>", Caps( Cmdline ), 1 ) ) {

      if ( Svl( sTime ) == 0 ) {
        // Only do this stuff if these metacommands exist
        GetProfileString( "intl", "sTime", ":", sTime, 2 );
      }
      // Get Time/Date Integer for current file
    	Jy = Cur_File_Time;

			// Setup File time string
    	jx = jy & 0xffff;
    	ftime_str = str_del(Make_Time_Str (jx >> 11,(jx >> 5) & 0x3f, 0), 6, 3);
    	if (xpos (sTime, ftime_str, 1) == 2)
      	ftime_str = Str_Del(Make_Time_Str (jx >> 11,(jx >> 5) & 0x3f, 0), 5, 3);

    	jx = jy >> 16;
    	fdate_str = make_date_str ((jx >> 9) + 1980, (jx >> 5) & 0x0f, jx & 0x1f);
  	}
    Jx = 1;
    while ( Jx = XPos( "<", Cmdline, Jx ) ) {
      if ( ( Jy = XPos( ">", Cmdline, Jx ) ) == 0 ) {
        break;
      }
      Jy = Jy - Jx - 1;
			Alias = Copy( Cmdline, Jx + 1, 1 );
      if ( XPos( Alias, "%~", 1 ) ) {
        TStr = Copy( CmdLine, Jx + 2, Jy - 1 );
      }
			else {
      	Alias = Copy( CmdLine, Jx + 1, Jy );
			}
      switch ( Caps( Alias ) ) {
				case "%" :                      // Environment variable
					TStr = Get_Environment( TStr );
					break;

				case "~" :                      // Global str variable
					TStr = Global_Str( TStr );
					break;

        case "LFN" :
          UseLFN = True;
          FName = GetLongName( FName );
          TStr = "";
          break;

        case "SFN" :
          UseLFN = False;
          FName = GetShortName( FName );
          TStr = "";
          break;

        case "FILE" :
          TStr = Truncate_Extension( FName );
          break;

        case "EXT" :
          TStr = Get_Extension( FName );
          break;

				case "NAME" :
					TStr = Truncate_Path( Truncate_Extension( FName ) );
					break;

				case "PATH" :
					TStr = Get_Path( FName );
					break;

				case "ME_PATH" :
					if ( UseLFN ) {
						TStr = GetLongName( Me_Path );
					}
					else {
						TStr = GetShortName( Me_Path );
					}
					break;

				case "COMSPEC" :
					if ( UseLFN ) {
						TStr = GetLongName( Comspec );
					}
					else {
						TStr = GetShortName( Comspec );
					}
					break;

				case "USER_PATH" :
					if ( UseLFN ) {
						TStr = GetLongName( User_Path );
					}
					else {
						TStr = GetShortName( User_Path );
					}
					break;

				case "MAC_PATH" :
					if ( UseLFN ) {
						TStr = GetLongName( GetUserMacroPath( ) );
					}
					else {
						TStr = GetShortName( GetUserMacroPath( ) );
					}
					break;

        case "DEFAULTS_PATH" :
					if ( UseLFN ) {
            TStr = GetLongName( _DefaultDir );
					}
					else {
            TStr = GetShortName( _DefaultDir );
					}
          break;

				case "USER_ID" :
					TStr = User_Id;
					break;

				case "CTIME" :                  // Put current time
					TStr = Time_Str;
					break;

				case "CDATE" :                  // Put current date
					TStr = Date;
					break;

				case "FTIME" :                  // Put file last save time
					TStr = FTime_Str;
					break;

				case "FDATE" :                  // Put file last save date
					TStr = FDate_Str;
					break;

        default:
          Jx += Jy + 2;
          Jy = 0;
      }
      if ( Jy ) {
        Cmdline = Str_Del( Cmdline, Jx, Jy + 2 );
        if ( Svl( TStr ) ) {
          Cmdline = Str_Ins( TStr, Cmdline, Jx );
        }
      }
    }
//#ifdef _Debug_
//	DebugLog( 1, "tcl-After ", "F=%s| %s", FName, Cmdline );
//#endif
	}
  return ( Cmdline );

}  // TranslateCmdline

str GetUserMacroPath( ) trans2
/******************* Multi-Edit STRING Macro Function ***********************

 NAME:         GetUserMacroPath()

 DESCRIPTION:  Returns the path to place user generated .MAC files in.

*****************************07-23-93 11:15am*******************************/
{
	if ( User_Path != _ConfigDir ) {
		return ( User_Path );
	}
	else {
		return ( Me_Path + "MAC\\" );
	}
}  // GetUserMacroPath

str GetUserPath( ) {
/****************************Multi-Edit Macro********************************

 NAME:         GetUserPath

 DESCRIPTION:  Gets the complete path pointing to the user directory, or
							 the Multi-Edit directory if user directories are not being
							 used.

 PARAMETERS:   if create_dirs is TRUE then it will create the user directory
							 if it doesn't exist.

 RETURNS:      A string containing the complete path name including ending
							 backslash.

*****************************12-21-92 02:05pm*******************************/

	return ( User_Path );

}  // GetUserPath

str CreateUserPath( str path, int copy_default )
{

  int  jx ;
  str  tstr[120];

  struct WIN32_FIND_DATA new_fd;
  struct DOS_FIND_DATA old_fd;
  int find_handle;

	path = Truncate_Path( path );

	tstr = user_path;
	path = tstr + path;

  find_handle = FindFirstFile( path, &new_fd, &old_fd );

  if( !find_handle )
	{
		if(  copy_default  )
		{
			tstr = _DefaultDir + truncate_path(path);
			if(!(jx = file_exists( tstr )))
			{
				tstr = me_path + truncate_path(path);
				jx = file_exists(tstr);
			}
			if(jx)
			{
				if(  tstr != path )
				{
					jx = Copy_File( tstr, path, false );
				}
			}
		}
	}
  else {
    FindClose( find_handle );
  }
	return( path );

}  // CreateUserPath

str TempFileName( str path ) trans2
{
  str TStr[ 1024 ] = Global_Str( "@Tmp_File_Path" );

	if ( Svl( TStr ) ) {
		TStr = TranslateCmdline( TStr, Path );
		if ( Copy( TStr, Svl( TStr), 1 ) != "\\" ) {
			TStr += "\\";
		}
		TStr += Path;
	}
	else {
		TStr = Path;
		TStr = CreateUserPath( TStr, FALSE );
	}
  return ( GetShortName( FExpand( TStr ) ) );

}  // TempFileName

int LocateDbPage( str fname, str page_title, int create_if_not_found  )
/*******************************************************************************

Description: Loads up the specified DB file (if it is not already
						loaded), and then searches for the specified page title.

Returns:    1 IF the title was found,
						0 If NOT found.

Parameters:   fname                   The db file name.
							page_title              The page Title.
							create_if_not_found     1 = Create page if not found.

							 (C) Copyright 1991 by American Cybernetics, Inc.
*******************************************************************************/
{
	str  tstr;
	int Path_Specified,l,c,r,o;
	int tRegExpStat = reg_exp_stat,   // JKP make sure these get restored
			tCase = ignore_case,
			result;

	if(  (Get_extension(fname) == '')  ) {
/* This provides support for a default DB file extension to be configured.  It
is overridden if the calling macro specifies an extension */
		if(  (Global_Str('@DB_EXTENSION') == '')  ) {
			fname = fname + '.DB';
		} else {
			fname = fname + '.' + Global_Str('@DB_EXTENSION');
		}
	}
	Path_Specified = (Get_Path(fname) != '');
	if(!path_specified)
	{
		tstr = user_path;
	}
	else
	{
		tstr = "";
	}
	if ( Switch_File( TStr + FName ) ){
		fname = file_name;
		error_level = 0;
	} else {
		if(  (Path_Specified == False)  ) {
			fname = CreateUserPath( fname, TRUE );
		}
		error_level = 0;
		if(  NOT( switch_file( fname ) )  ) {
			Switch_Window( window_count );
			Create_Window;
			Load_File( fname );
			window_attr = $81;
		}
	}
	result = 1;
	if(  error_level == 0  ) {
		reg_exp_stat = TRUE;
		ignore_case  = TRUE;    // JKP added to take care of titles in lower case
		if(  page_title != ''  ) {
			if( global_str( '~SETCONFIG_' + str( window_id ) ) == page_title ) {
				GET_MARK_RECORD( 1, 3, l, c, r, o );
				goto_line( l );
				goto_col( 1 );
				if(  find_text( '%|12' + make_literal(page_title) + '$|| ' ,1,_OldExp)) {
					result = TRUE;
					goto exit;
				}
			}
			tof;
			if(  NOT(Find_Text( '%|12' + make_literal(page_title) + '$|| ' ,0,_OldExp))  ) {
				result = 0;
				if( create_if_not_found ) {
					EOF;
					Insert_mode = true;
					if(  c_col > 1  ) {
						CR;
					}
					TEXT( '|12' + page_title );
					result = 1;
				}
			}
			if( result ) {
				set_global_str( '~SETCONFIG_' + str( window_id ), page_title );
				set_mark_record( 1, 3, c_line, c_col, 1, 1 );
			}
		} else {
			tof;
		}
	} else {
		result = 0;
	}
exit:
	reg_exp_stat = tRegExpStat;
	ignore_case  = tCase;
	return(result);
}

#DEFINE GDR_CASESENSITIVE 1

int GetDbRecord(
/****************************************************************************
Description:  Finds and returns the specified record in a .DB file.
Returns:
							1 if found
							0 if not found, but first record is stored in /GLO=
						 -1 if not found and there are no records.
						 -2 if the DPT is not found in the DB file.
						 -3 if the DB file is not found.

This only works for string and integer fields
****************************************************************************/
					str fname[128],      // db filename
					str dpt[80],         // data page title
					str dbf,             // field name
					str fv,              // field value
					int rec_num,         // record # to return (overrides fv
															 //   and dbf).  Example:  If /#=3 then the
															 //   3rd record will be returned.
					int flags,           // 1 = case sensitive search
					str global_name[20], // name of global variable to store record
					int remove_file,     // if TRUE, then remove DB file from memory
															 //    after operation
					str misc             // Misc parameters
															 //   /AGLO=n  name  of global integer
															 //            to store total #  of
															 //            records
															 //   /LD=str  Delimit to use, default is
															 //            ASCII 127
															 //   /RGLO=n  name of global integer
															 //            to store the # of the found
															 //            record.
															 //   /RS=n    the number of the record to
															 //            start searching from
								 )


{
	int Active_Window = Window_Id,
					Db_Window = 0,
					T_Reg_Exp_Stat = Reg_Exp_Stat,
					T_Ignore_Case = Ignore_Case,
					T_Refresh = Refresh,
					Start_Records,
					result,
					Record_Amount;
	int RecordStart = Parse_Int( "/RS=", Misc );

	ignore_case = true;
	char Delimit = Parse_Str('/LD=',misc);
	if(  (Delimit == '|0')  ) {
		Delimit = "\x7F";
	}
	Refresh = False;

	if( !LocateDbPage( fname, dpt, false ))
	{
		result = -3;
		goto exit;
	}

	/*
	if(  (Truncate_Path(fname) != Truncate_Path(File_Name))  ) {
			make_message( fname + " " +  file_name );
			beep;
			result = -3;
			Goto EXIT;
	}
	if (Svl(Dpt)) {
		if (Caps(Get_Line) != ('|12' + DPT)) {
			result = -2;
			Goto EXIT;
		}
	}

	 */

	fname = file_name;
	db_window = window_id;


	reg_exp_stat = TRUE;
	Start_Records = C_Line;
	Eol;
	if (Find_Text('%{|12}||{@*@*@*@*START@*@*@*@*}',0,_OldExp)) {
/* If we found a data page title, assume no header in this db */
		if (Cur_Char != '|12') {
			Start_Records = C_Line;
			if(  (Find_Text('%|12',0,_OldExp) == False)  ) {
				Eof;
				if(  (C_Col > 1)  ) {
					Down;
				}
			}
		}
	} else {
		Eof;
		if(  (C_Col > 1)  ) {
			Down;
		}
	}
	++Start_Records;
	Record_Amount = C_Line - Start_Records;

	if(parse_str('/AGLO=', misc) != '')
		Set_Global_Int(Parse_Str('/AGLO=',misc),Record_Amount);


	if(  (Record_Amount < 1)  ) {
		result = -1;
		Goto EXIT;
	}
	if(  (Rec_Num)  ) {
		if(  ((Rec_Num > Record_Amount) | (Rec_Num < 1))  ) {
			result = 0;
			Goto_Line(Start_Records);
		} else {
			result = 1;
			Goto_Line(Start_Records + Rec_Num - 1);
		}
	}
//   else {
//     Goto_Line(Start_Records);
	else if ( RecordStart < Record_Amount ) {
		Goto_Line( Start_Records  + RecordStart );
		Goto_Col(1);
		if ( flags & GDR_CASESENSITIVE ) { // case sensitive field search
			ignore_case = false;
		}
		reg_Exp_Stat = TRUE;


		result = Search_Fwd(Delimit + dbf + '=' +
									fv  + Delimit + '||$', Record_Amount - RecordStart );
//                   fv  + Delimit + '||$', Record_Amount);
	}
	else {
		Result = 0;
		Goto_Line( Start_Records );
	}
	Set_Global_Str( Global_Name, Get_Line );
	if ( Parse_Str( "/RGLO=", Misc )  != "" ) {
		Set_Global_Int( Parse_Str( "/RGLO=", Misc), C_Line - Start_Records + 1 );
	}

EXIT:
	if(  remove_file  ) {
		if(  (Switch_Win_Id(DB_Window))  ) {
			Delete_Window;
		}
	}
	Reg_Exp_Stat = T_Reg_Exp_Stat;
	Ignore_Case = T_Ignore_Case;
	Switch_Win_Id(Active_Window);
	Refresh = T_Refresh;
	return(result);
}

int CheckDupFields (str dbpage, str dbline[max_line_length], str fielddata, ...)
{
	int tRefresh  = Refresh;
	int dup       = FALSE;

	Refresh       = False;

	tof;
	if (  find_text("%\f" + dbpage + "$| ",0, _OldExp)  )  // find start of header
	{
		down;
		int s_line    = c_line;
		int e_line;
		int num_lines = 0;

		if (find_text ("%\f", 0, _OldExp))
		{
			e_line    = c_line;
			num_lines = e_line - s_line;
		}

		goto_line (s_line);

		int pc  = 0;
		dup = False;

		while ( Get_Param_Type (++pc) == 1 )
		{
			str fstr = Get_Param_Str (pc) + fielddata;

			while (find_text (fstr, num_lines, 0))
			{
				if (dbline != get_line  )
				{
					dup = True;
					break;
				}
				goto_col (1);
				down;
				num_lines = e_line - c_line;
			}
		}

	}
	Refresh      = tRefresh;
	return (dup);
}



str SearchPath( str fname, fpath )
/*******************************************************************************
Description: Searches for a filename in a given path
						TranslateCmdLine is called to parse out any metacommands BEFORE
						the search takes place.

Returns:    complete path and filename, or a NUL string if
						the search was not successful.

*******************************************************************************/
{
	int  jx, jy ;
	str tpath ;

	fname = TranslateCmdLine( fname, "" );
	tpath = TranslateCmdLine( fpath, "" );
	jy = 0;
	fpath = '';
	goto first_time;
LOOP:
	if(  jy > svl(tpath)  ) {
		return('');
	}

	jx = XPos( ';', tpath, jy + 1 );
	if(  jx == 0  ) {
		jx = svl( tpath ) + 1;
	}
	fpath = Copy( tpath, jy + 1, jx - jy - 1 );
	if(  (SVL(fpath) > 0) & (copy(fpath,SVL(fpath),1) != '\')  ) {
		fpath = fpath + '\';
	}
	jy = jx;

first_time:
	if(  file_exists( fpath + fname )  ) {
		return_int = 1;
		return(fexpand(fpath + fname));
	}
	goto loop;

}

int CursorInBlock( int Offset = XPos( "/O", MParm_Str, 1 ) ) Trans2 {
/******************************************************************************
                               Multi-Edit Macro
															 28-Jun-95  13:10

  Function: Check if cursor is in a marked block.
	Entry		: int Offset - True to offset cursor - 1 when non-inclusive block
												 marked.  ( "/O" )
  Exit    : int
              False = Cursor NOT in block or no block marked.
              True	= Cursor in block.

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/

  int Result = Marking;
	int Jx;

	if ( !Marking ) {
		Result = Block_Stat && ( C_Line >= Block_Line1 ) &&
				( C_Line <= Block_Line2 );
  	if ( Result && ( Block_Stat != _LinBlock ) ) {
    	if ( Block_Stat == _ColBlock ) {
      	Result &= ( C_Col >= Block_Col1 ) && ( C_Col <= Block_Col2 );
			}
    	else if ( Block_Stat == _StrBlock ) {
				Jx = !Stream_Block_Mode && Offset;
      	Result = ( !( ( ( C_Line == Block_Line1 ) && ( C_Col < Block_Col1 ) ) ||
          	( ( C_Line == Block_Line2 ) && ( ( C_Col - Jx ) > Block_Col2 ) ) ) );
			}
		}
 	}
  return ( Result );

}  // CursorInBlock

int PushBlock( int Hide = XPos( "/H", MParm_Str, 1 ) ) Trans2 {
/******************************************************************************
                               Multi-Edit Macro
                               20-Jun-93  19:09

  Function: Pushes the current marked block info on a block stack.
  Entry   : int Hide 		- !0 to turn block off after being pushed ( "/H" )
  Exit    :	int 				- # of the pushed block.

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/

	str GName = "@BLK" + Str( Window_Id ) + "_";

  int Cnt = 0;

	if ( Block_Stat ) {
  	Cnt = Global_Int( GName + "#" ) + 1;
  	Set_Global_Str( GName + Str( Cnt ),
    	"/S="  + Str( Block_Stat ) +
    	"/LX=" + Str( Block_LineX ) +
    	"/CX=" + Str( Block_ColX ) +
    	"/L1=" + Str( Block_Line1 ) +
    	"/L2=" + Str( Block_Line2 ) +
    	"/C1=" + Str( Block_Col1 ) +
    	"/C2=" + Str( Block_Col2 ) +
    	"/M="  + Str( Marking ) +
			"/SM=" + Str( Stream_Block_Mode )
      	);
  	Set_Global_Int( GName + "#", Cnt );
		if ( Hide ) {
			Block_Off;
		}
// 		Make_Message( Global_Str( GName + Str( Cnt ) ) );
	}
	return ( Cnt );

}  // PushBlock

int PopBlock( int Show = XPos( "/S", MParm_Str, 1 ) ) Trans2 {
/******************************************************************************
                               Multi-Edit Macro
                               20-Jun-93  19:09

  Function: Pops block information off ot the block stack.
  Entry   : int Show 		- !0 to show popped block else throws info away ( "/S" )
  Exit    :	int 				- # of the block poped.

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/

	str GName = "@BLK" + Str( Window_Id ) + "_";
	str TStr[ 100 ];

  int Cnt = Global_Int( GName + "#" );

  if ( Cnt > 0 ) {
    TStr = Global_Str( GName + Str( Cnt ) );
		if ( Show ) {
			Block_Off;
    	Block_Stat  = Parse_Int( "/S=", TStr );
    	Block_Linex = Parse_Int( "/LX=", TStr );
    	Block_Colx  = Parse_Int( "/CX=", TStr );
    	Block_Line1 = Parse_Int( "/L1=", TStr );
    	Block_Line2 = Parse_Int( "/L2=", TStr );
    	Block_Col1  = Parse_Int( "/C1=", TStr );
    	Block_Col2  = Parse_Int( "/C2=", TStr );
    	Marking     = Parse_Int( "/M=", TStr );
			Stream_Block_Mode = Parse_Int("/SM=", TStr );
			Redraw;
// 			Make_Message( TStr );
		}
		Set_Global_Str( GName + Str( Cnt ), "" );
    Set_Global_Int( GName + "#", Cnt - 1 );
  }
	return ( Cnt );

}  // PopBlock

void MarkBlock(
			int Type 	 	= Parse_Int( "/T=", MParm_Str ),
			int BlkOff 	= Parse_Int( "/O=", MParm_Str ),
			int Extend 	= Parse_Int( "/E=", MParm_Str ),
			int Message = Parse_Int( "/NM=", MParm_Str ) == 0,
			str Misc 		= MParm_Str
) trans2 {
/******************************************************************************
                               Multi-Edit Macro
															 15-Jul-93  15:43

  Function: Mark, extend or unmark a block.

  Entry   : int Type 		Block Type ( /T=int )
								1				- Line block
								2				-	Column block
								3				-	Inclusive stream block
								4				-	Noninclusive stream block.
							other			-	Block off

						int BlkOff	Will not turn block off if block is of different type
												( /O=1 )

						int Extend	Extend current block ( /E=int )
								1				- Extend end of block to cursor
								2				- Extend beginning of block to cursor

						int Message	Show messages when True ( /NM=1 no messages )
						str Misc		Additional parameters for future expansion

  Exit    : None

							 Copyright (C) 1995 by American Cybernetics, Inc.
********************************************************************( ldh )***/

	int SavRefresh = Refresh;
	int SavPB 		 = Persistent_Blocks;
  int XType 		 = ( Extend == 2 );
	int	K1 				 = Key1;
	int K2 				 = Key2;
	int Jx;

//  str Key_Name[ 30 ] = Make_Key_Name( Make_Word( K1, K2 ) );  // Store key name
  str Key_Name[ 30 ] = Make_Key_Name( Make_Word( Key1, Key2 ) );  // Store key name
	str TStr[ 20 ];

  if ( Extend && Block_Stat) {          // Extend marked block
    if ( Blkoff ) {
			Marking = True;
		}
		Persistent_Blocks = True;
    if ( Block_Stat == _LinBlock ) {     // Line mark
      if ( ( C_Line < Block_Line1 ) || ( XType && CursorInBlock( False ) ) ) {
				Block_Line1 = C_Line;
				Block_LineX = Block_Line2;
			}
			else {
				Block_Line2 = C_Line;
				Block_LineX = Block_Line1;
			}
		}
    else if ( Block_Stat == _StrBlock ) {  // Stream mark
      if ( ( C_Line < Block_Line1 ) ||
          ( ( C_Line == Block_Line1 ) && ( C_Col < Block_Col1 ) ) ||
          ( XType && CursorInBlock( True ) ) )
			{
				Block_Line1 = C_Line;
				Block_LineX = Block_Line2;
				Block_Col1  = C_Col;
				Block_ColX  = Block_Col2;
			}
			else {
				Block_Line2 = C_Line;
				Block_LineX = Block_Line1;
				Block_ColX  = Block_Col1;
        if ( Stream_Block_Mode ) {
					Block_Col2 = C_Col;
				}
				else {
					Block_Col2 = C_Col - 1;
				}
			}
		}
		else {                              // Column mark
      if ( ( C_Line < Block_Line1 ) || ( XType && CursorInBlock( False ) ) ) {
				Block_Line1 = C_Line;
				Block_LineX = Block_Line2;
				if ( C_Col > Block_Col2 ) {
					Block_ColX = Block_Col1;
					Block_Col2 = C_Col;
				}
				else {
					Block_Col1 = C_Col;
					Block_ColX = Block_Col2;
				}
			}
			else {
				Block_LineX = Block_Line1;
				block_line2 = C_Line;
				if ( C_Col < Block_Col1 ) {
					Block_Col1  = C_Col;
					Block_ColX  = Block_Col2;
				}
				else {
					Block_ColX = Block_Col1;
					Block_Col2 = C_Col;
				}
			}
		}
		Redraw;
		Persistent_Blocks = SavPB;
	}
	else if ( ( Type > _StrBlockNI ) || ( Type < _LinBlock ) ) {  // Turn block off
		Block_Off;
		BlkOff = True;
	}
  else if ( BlkOff && CursorInBlock( True ) ) {

		Refresh = False;
		if ( !Marking ) {
      Rm( "MarkBlock /E=1" );
		}
		Marking = True;

		switch ( Type ) {
			case _LinBlock :
				if ( Block_Stat == _LinBlock ) {
					Block_Off;
				}
				else {                          // Change to line mark
					TStr = "Line";
					Block_Stat = _LinBlock;
				}
				break;

			case _ColBlock :
				if ( Block_Stat == _ColBlock ) {
					Block_Off;
				}
				else {                          // Change to col mark
					TStr = "Columnar";
					Block_Stat = _ColBlock;
				}
				break;

			case _StrBlock :
				if ( ( Block_Stat == _StrBlock ) && Stream_Block_Mode ) {
					Block_Off;
				}
				else {                          // Change to inclusive mark
					TStr = "I-Stream";
					Stream_Block_Mode = True;
					Block_Stat = _StrBlock;
				}
				break;

			case _StrBlockNI :
				if ( ( Block_Stat == _StrBlock ) && !Stream_Block_Mode ) {
					Block_Off;
				}
				else {                          // Change to noninclusive mark
					TStr = "NI-Stream";
					Stream_Block_Mode = False;
					Block_Stat = _StrBlock;
				}
		}
		Goto_Col( C_Col );
		Refresh = SavRefresh;
		Redraw;
	}
	else if ( Marking ) {
		Block_End;
	}
	else {
		switch ( Type ) {
			case _LinBlock :									// Line block
				Block_Begin;
				TStr = "Line";
				break;

			case _ColBlock :									// Column block
				Col_Block_Begin;
				TStr = "Columnar";
				break;

			case _StrBlock :									// Inclusive steam block
				Stream_Block_Mode = True;
				Str_Block_Begin;
				TStr = "I-Stream";
				break;

			case _StrBlockNI :     						// Noninclusive stream block
				Stream_Block_Mode = False;
				Str_Block_Begin;
				TStr = "NI-Stream";
		}
	}
	if ( Jx = Block_Stat) {
		if ( Jx == _StrBlock ) {
			Jx += !Stream_Block_Mode;
		}
  //  Set_Global_Int( "@Last_Block_Type", Jx );
	}
	if ( Message ) {
		if ( Extend ) {
			Make_Message( "Block extended." );
		}
		else if ( Marking ) {
			if ( BlkOff ) {
        Make_Message( "Marking " + TStr + " block, press " + Key_Name +
            " to turn block off." );
			}
			else {
        Make_Message( "Marking " + TStr + " block, press " + Key_Name +
            " to end block." );
			}
		}
		else if ( BlkOff ) {
			Make_Message( "Block turned off." );
		}
		else {
			Make_Message( "Block marked." );
		}
	}
}  // MarkBlock


int GetFileTime( str FileName ) {
/******************************************************************************
															 Multi-Edit Macro
																9/28/95 6:15PM

  Function: Return the time of FileName.
  Entry   : str FileName  - Name of file to get the time for
  Exit    : int						- File time

							 Copyright (C) 1995 by American Cybernectic, Inc.
********************************************************************( ldh )***/


	int FileTime = 0;
  int hFindFile = 0;

  struct WIN32_FIND_DATA NewFd;
  struct DOS_FIND_DATA   OldFd;

	hFindFile = FindFirstFile( FileName, &NewFd, &OldFd );
	if ( hFindFile ) {
		FileTime = OldFd.Time;
		FindClose( hFindFile );
	}
	return ( FileTime );

}  // GetFileTime
