OBJECT SET ENABLED returns 0, not true or false v18 R2

Perhaps nut this one worked for me. I have run it on more than one db. You should test for yourself



Sorry, I didn’t mean that your code doesn’t work … I tried it and it does. But when I copy/pasted it from your post I had to fix some issues that were due to it not being formatted as code.

This screenshot might explain what I mean a bit better. I’ve typed the regex in the same both times, but see the difference in the preview when you don’t have the ```4d and ``` around it.


the posted code had lots of quote/end-quotes (not ").

I have used my “moderator” access to clean it up.


Is this code now ready to run ‘as is’ ?

And to do that would I simply copy and paste it into a 4D method and then use EXECUTE to run the method?

Sorry if my questions are basic, I know that ideally I would study the code to make sure that I understood it thoroughly so I could tell if it was run-ready without asking - but time is pressing and regex is not my thing.

As a safeguard, normally I would backup via Time Machine beforehand so that I can readily revert the structure; is 4D backup also suited to this task?

Sorry, I can not take responsibility for this code. I only cleaned it up to improve legibility,

OK thanks, that is understandable.

Would you be willing to share the fixed code?

I have tried the code as it apears now in the post but I get errors in several places when I execute it (in debug mode).

Hi David,

I’ve included the copy that I have below.

Disclaimer: I have not run the code against my actual application code, only some samples to try it out. And I’ve only tested _O_ENABLE BUTTON.

Whenever doing automated code replacement I always output the before and after of all methods that are being changed, then use a diff tool to do spot checks. You can also use the list to design test cases that target everywhere that has changed. And take a copy of your structure beforehand. :wink:

Below are two situations that I know of that won’t be replaced.

  1. The last line of the method. Because the regex is looking for \r at the end, if the old command is on the last line of the method the \r isn’t there and it doesn’t match. If you think you might have that situation, a quick hack to resolve it would be to add a \r to the end of the method code before doing the Match regex (elephant in Cairo)
  2. Comments on the end of the line that contain a ). In this case the ;True or ;False gets added to the comment instead of the end of the command. I doubt you’ll need to worry about this though - it’s unlikely but not impossible. Just do Search References afterwards to see if any occurrences are missed.
  // Method Replace_compiler_directives replaces deprecated compiler
  // #SYNTAX: Replace compiler directives
  // none

  // #DATE CREATION: 02/02/2016 #AUTHOR: Bertrand SOUBEYRAND
  // #DATE MODIFICATION: 08/02/2016
  // #NOTE: This methods runs on 4D v13 and later

  // If you find this code useful, so send a mail!

ARRAY TEXT($rT_Paths;0)
ARRAY TEXT($rT_Code;0)
METHOD GET PATHS(Path all objects;$rT_Paths)

METHOD GET CODE($rT_Paths;$rT_Code)
$T_This_path:=METHOD Get path(Path project method;Current method name)
$L_Pos:=Find in array($rT_Paths;$T_This_path)
$T_This_path:=METHOD Get path(Path project method;"ReplaceInCompiler_methods")

$L_Pos:=Find in array($rT_Paths;$T_This_path)
If ($L_Pos>0)  //AS: 2020-06-29 - Added
End if 

ARRAY TEXT($rT_Old_Directive;6)
ARRAY TEXT($rT_New_Directive;Size of array($rT_Old_Directive))

  // added 02/08/2016
$rT_Old_Directive{1}:=Command name(293)+"\\(\\d{1,3};"  // c_string
$rT_Old_Directive{2}:=Command name(282)+"\\("  // c_integer
$rT_Old_Directive{3}:=Command name(218)+"\\(\\d{1,3};"  // array string
  //$rT_Old_Directive{4}:="\r(_O_ENABLE BUTTON)(\\()(.)(\\))(.)\r"  // _o_ENABLE BUTTON
  //$rT_Old_Directive{5}:="\r(_O_DISABLE BUTTON)(\\()(.)(\\))(.)\r"  // _o_DISABLE BUTTON
  //$rT_Old_Directive{6}:="\r(_O_REDRAW LIST)(\\()(.)(\\))(.)\r"  // _o_DISABLE BUTTON
  //AS: 2020-06-29 - Escaped carriage returns and added *'s (original was corrupted by forum)
$rT_Old_Directive{4}:="\\r(_O_ENABLE BUTTON)(\\()(.*)(\\))(.*)\\r"  // _o_ENABLE BUTTON
$rT_Old_Directive{5}:="\\r(_O_DISABLE BUTTON)(\\()(.*)(\\))(.*)\\r"  // _o_DISABLE BUTTON
$rT_Old_Directive{6}:="\\r(_O_REDRAW LIST)(\\()(.*)(\\))(.*)\\r"  // _o_DISABLE BUTTON

$rT_New_Directive{1}:=Command name(284)+"("
$rT_New_Directive{2}:=Command name(283)+"("
$rT_New_Directive{3}:=Command name(222)+"("
$rT_New_Directive{4}:=Command name(1123)+"("
$rT_New_Directive{5}:=Command name(1123)+"("

For ($i;1;Size of array($rT_Paths))
	  // for each method
	For ($j;1;Size of array($rT_Old_Directive))
		  // for each directive
			  // for each found
			ARRAY LONGINT($rL_Length;0)
			$B_Match:=Match regex($rT_Old_Directive{$j};$rT_Code{$i};$L_Start;$rL_Pos;$rL_Length)
			If ($B_Match)
				If (Position("O_C_string";$T_Old)>0)
					$rT_Code{$i}:=Replace string($rT_Code{$i};$T_Old;$rT_New_Directive{$j})
					$T_Old:=Replace string($T_Old;"_O_C_STRING(";"// string length was ";1)""
					$T_Old:=Replace string($T_Old;";";"";1)""
				End if 
				If (Position("_O_ARRAY STRING";$T_Old)>0)
					$rT_Code{$i}:=Replace string($rT_Code{$i};$T_Old;$rT_New_Directive{$j})
					$T_Old:=Replace string($T_Old;"_o_ARRAY STRING(";"//array string length was ";1)
					$T_Old:=Replace string($T_Old;";";"";1)""
					If (Substring($rT_Code{$i};$ParenPos_L;2)="))")
					End if 
				End if 
				If (Position("_O_C_INTEGER";$T_Old)>0)
					$rT_Code{$i}:=Replace string($rT_Code{$i};$T_Old;$rT_New_Directive{$j})
					$T_Old:=Replace string($T_Old;"_O_C_INTEGER(";"// was integer";1)
					$T_Old:=Replace string($T_Old;";";"";1)
				End if 
				If (Position("_O_ENABLE BUTTON";$T_Old)>0)
					If (Size of array($rL_Pos)=5)
					End if 
					  //AS: 2020-06-29 - Added // back into below (was removed by forum)
					$rT_Code{$i}:=Substring($rT_Code{$i};1;($rL_Pos{0}))+"// Command Replaced "+Substring($rT_Code{$i};$rL_Pos{0}+1;($rL_Length{0}-1))+"OBJECT SET ENABLED("+Substring($rT_Code{$i};$rL_Pos{3};$rL_Length{3})+"; true)"+$cmts_txt+"\r"+Substring($rT_Code{$i};($rL_Pos{0}+$rL_Length{0}))  //$start_L:=$start_aL{0}+$rL_Length{0}+Length(" Command Replaced ")
					  //$T_Old:=Replace string($T_Old;"_o_ENABLE BUTTON(";"// was _o_ENABLE BUTTON ";1)
					  //$T_Old:=Replace string($T_Old;";";"";1)
				End if 
				If (Position("_O_DISABLE BUTTON";$T_Old)>0)
					If (Size of array($rL_Pos)=5)
					End if 
					  //AS: 2020-06-29 - Added // back into below (was removed by forum)
					$rT_Code{$i}:=Substring($rT_Code{$i};1;($rL_Pos{0}))+"// Command Replaced "+Substring($rT_Code{$i};$rL_Pos{0}+1;($rL_Length{0}-1))+"OBJECT SET ENABLED("+Substring($rT_Code{$i};$rL_Pos{3};$rL_Length{3})+"; false)"+$cmts_txt+"\r"+Substring($rT_Code{$i};($rL_Pos{0}+$rL_Length{0}))  //$start_L:=$start_aL{0}+$rL_Length{0}+Length(" Command Replaced ")
					  //$T_Old:=Replace string($T_Old;"_o_ENABLE BUTTON(";"// was _o_ENABLE BUTTON ";1)
					  //$T_Old:=Replace string($T_Old;";";"";1)
				End if 
				If (Position("_O_REDRAW";$T_Old)>0)
					If (Size of array($rL_Pos)=5)
					End if 
					  //AS: 2020-06-29 - Added // back into below (was removed by forum)
					$rT_Code{$i}:=Substring($rT_Code{$i};1;($rL_Pos{0}))+"// Command Replaced "+Substring($rT_Code{$i};$rL_Pos{0}+1;($rL_Length{0}-1))+"redraw("+Substring($rT_Code{$i};$rL_Pos{3};$rL_Length{3})+")"+$cmts_txt+"\r"+Substring($rT_Code{$i};($rL_Pos{0}+$rL_Length{0}))  //$start_L:=$start_aL{0}+$rL_Length{0}+Length(" Command Replaced ")
					  //$T_Old:=Replace string($T_Old;"_o_ENABLE BUTTON(";"// was _o_ENABLE BUTTON ";1)
					  //$T_Old:=Replace string($T_Old;";";"";1)
				End if 
			End if 
		Until ($B_Match=False)
	End for 
	If ($B_Modified)
		  //AS: 2020-06-29 - Commented out
		METHOD SET CODE($rT_Paths{$i};$rT_Code{$i})
		  //AS: 2020-06-29 - Commented out
	End if 
End for 

ALERT("job done in "+String((Milliseconds-$L_Milli)*0.001)+" seconds")

  // EOM

Hello Adam, many thanks for posting the code and the additional advice.

I enjoyed https://en.wikipedia.org/wiki/Elephant_in_Cairo Regex is the thing that makes me nervous about all of this, for the reason that might be nicely illustrated by deploying the algorithm described in the link but substituting “MyUnderstanding” for “Elephant”. No matter how hard I traverse the continent (your posted code) I won’t find understanding because I know not Regex.

So I am going to put some effort into understanding the Regex used in the code; and I will also use a diff tool - to compare your fixed code with the code where it was originally posted by Charles Miller. I might find out if it is different in the places that threw an error when I ran the original version to test it.

After that … I will try running it on a copy of the actual application and if it works I will search for any anomalies.

I am extremely nervous about running something which will make so many changes on the actual application, without being sure that I fully understand it. This is a production database which populates and receives orders for a live retail product website.

I start off pretty much drained already. Over the last very few months most things I rely on have broken, starting with:

  • My TimeMachine backup disc (replaced);

  • My laptop (replaced but with a new 16in machine which only runs Catalina and so forced a change to 4D v.18 and the issue now with 18.2)

  • My website hosting company upgraded their MySql server version which broke my website and caused me much pain and suffering trying to update PHP / MySql scripts (I have poor skills with those two) on the live web server whilst constantly reverting to part-working scripts whenever a visitor landed on the site.

  • Some time before all this it was a forced PHP version upgrade.

So now easy does it: fortunately I have already manually updated _O_ENABLE /DISABLE BUTTON in parts of the user interface which are most used and I can do more this way as the need arises.

I’ll aim to report back on progress … but I might be gone for some time. :upside_down_face:

I like to use this site which highlights the sub-elements of your expression and gives an explanation of what each element is doing. The only thing is that it uses javascript regex which has a slightly different syntax than ICU regex which 4D uses. But for the purposes of understanding and testing a regex it is good. For the regex in this code there’s no difference between javascript and ICU syntax.

Hope it all goes well.

Hi David,
some thoughs (I hope not too much)…

If automatic replacement seems dangerous, you can use code to find and open only methods containing a piece of code supposed to be replaced then replace it “by hand”. I often have to use code to find pieces of code that “Find in design” cannot find and/or replacement cannot be made automatically. You can also pretend to, or log for control, to be sure you get what you expect (before boiling it all up):

$log_c:=new collection
For(each method)
  //process the method
    //update the method
  end if
End for
SET TEXT TO PASTEBOARD($log_c.join("\r"))

With regex, I think it’s easier to divide and conquer: cut the code in lines, then process each line as shown above:

$lineOfCode_c:=Split string($code_t;"\r")

This will allow you to use simpler regex patterns, for example:

$obsoleteCommand= "^_o_"  //start text anchor + _o_
$comments:="  //.*$"  //2 spaces + 2 slashes + anything + end text anchor

Processing all lines of all methods may take a while. If you need it to go faster, you can use a “whole method probe” rough pattern to immediately dismiss or process the method. Don’t forget the good old Position BTW, not as powerful as a regex to match complicated patterns but with simple patterns it’s much faster, specially when using * as last parameter. For example:

$rough:="\r_o_"  //a line starting with an obsolete command
For (each method)
 METHOD GET CODE($methodPath;$wholeMethodCode)
 if(position($rough;$wholeMethodCode;*)>0)  //the method contains an obsolete command uncommented
  //split into separated lines and process each line
 End if
End for

Be careful with “broken” lines of code, those with backslash “” at end, I use this regex for it:

Case of 
	: (Match regex("\\\\$";$lineOfCode;1))
        //do something
End case

Here’s the code I’ve used (old, from v12). I changed some things before pasting, the original context made it a bit complicated, but not tested…

  //MP_replaceOldDirComp (->txt{;->arrDirComp) -> text
  //remplace dans txt les directives de compilation obsoletes :
  //  C_ALPHA(xx; -> C_TEXTE( 
  //#NI ne pas remplacer dans les commentaires

  //© Arnaud de Montard * 20/01/11, 14:23:33


ARRAY TEXT($alReplaceDC;0)
APPEND TO ARRAY($alReplaceDC;282)
APPEND TO ARRAY($alReplaceDC;293)
APPEND TO ARRAY($alReplaceDC;218)

For ($i;1;Size of array($alReplaceDC))
	Case of 
		: ($alReplaceDC{$i}=293)  //c_alpha -> c_text
			$tFind:=Command name(293)+"\\([0-9]*;"  //C_ALPHA([digits];
			$tReplace:=Command name(284)+"("  //C_TEXTE(
			While (Match regex($tFind;$tCodeNew;1;$lPos;$lLong))
				$tCodeNew:=Delete string($tCodeNew;$lPos;$lLong)
				$tCodeNew:=Insert string($tCodeNew;$tReplace;$lPos)
			End while 
		: ($alReplaceDC{$i}=282)  //c_integer -> c_longint
			$tFind:=Command name(282)+"("  //C_ENTIER(
			$tReplace:=Command name(283)+"("  //C_ENTIER LONG(
			While ($lPos>0)
				$tCodeNew:=Delete string($tCodeNew;$lPos;$lLong)
				$tCodeNew:=Insert string($tCodeNew;$tReplace;$lPos)
			End while 
		: ($alReplaceDC{$i}=218)  //arr alpha -> arr text
			$tFind:=Command name(218)+"\\([0-9]*;"  //TABLEAU ALPHA([digits];
			$tReplace:=Command name(222)+"("  //TABLEAU TEXTE(
			While (Match regex($tFind;$tCodeNew;1;$lPos;$lLong))
				$tCodeNew:=Delete string($tCodeNew;$lPos;$lLong)
				$tCodeNew:=Insert string($tCodeNew;$tReplace;$lPos)
			End while 
	End case 
End for 


Thanks. I plan on trying to take care of all of these when we upgrade to v18 … which we have to do by the end of the year if we want to stay supported.

It is a lesson to deal with these things straight away, not when they are about to be removed from the language :grinning:

I have been looking at A different Regex site but now I can ponder and compare yours as well. Thanks.

I’ll add this to the armoury; it would be the way to go if I can’t get anywhere with the automatic methods. There’s a lot of help being offered that I am trying to absorb :face_with_monocle:. Thanks.

I would encourage you do do it ASAP… I always ran the method that replaces c_alpha, array alpha, c_integer without asking myself any questions and never noticed any problem after, interpreted or compiled. It’s nothing more than setting declarations to what the compiler is already doing since v11.

With array integer it’s not so simple, when it’s used as below changing the array type will cause an error:
selection to array([aTable]integerField;$integerArray)

You are right. We are due to branch our code on Monday ready for our next release … so I’ll probably do it after that.

That explains why ARRAY INTEGER is not obsolete I suppose. We don’t use integer arrays very much, so I’ll probably just do that one by hand.

Exactly. If you have to store integer values never exceeding MAXINT in a huge table, it’s worth using the integer field type, it’s half a longint, better for performances (I/O, network).

Coming late here.
I confirm to have had some strange behaviors when mixing

OBJECT SET ENABLED(varname;$is_enabled)

You modify with one set, and the other do not work with no effect.
I solved it having my hands dirty in one shoot. Then it works fine.
And as explained, using named variable for buttons, you were able to get plenty of side effects manipulating one, but all of them in the Form chain.

I confirm it is mandatory to change all of it. By code or by hands, dirty again…

Hello Adam,

I’ve being trying your variation of the code that Charles Miller posted.

It ran with three errors (’’’’ terminating the lines):

$T_Old:=Replace string($T_Old;"_O_C_STRING(";"// string length was “;1)”"
$T_Old:=Replace string($T_Old;";";"";1)""

I fixed these and then had partial success in that ENABLE BUTTON / DISABLE BUTTON were updated in some places but not in many, many others. I have tried to figure this out from the code but I can’t detect a pattern so far.

Have you got any suggestions as to why it doesn’t work universally through all types of locations. The button settings are used a a variety of methods - the objects themselves, form methods, project methods.