Can't turn code into a function

Hi all. I’m trying to convert the code into a function. This code in the specified line swaps these characters in each pair of characters. But when I try to make it into a local function, I get nothing. The function neither prints nor returns a result. The source code is this:

:local number "8350000048F0"
:local len [:len $number]
:local tmpNum [:toarray ""]
:local realNum [:toarray ""]
:local result

:local counter 0
while ( $counter<$len ) do={
    :set $tmpNum ($tmpNum, [:pick $number $counter ($counter+1)] )
    :set $counter ($counter + 1)
};

:local counter 0
while ( $counter<$len ) do={
    :if ( ($counter % 2) = 0) do={
        :set $realNum ($realNum, ($tmpNum->($counter+1) ) )
    } else={
        :set $realNum ($realNum, ($tmpNum->($counter-1) ) )
    }
  :set $counter ($counter + 1)
};

:foreach num in=$realNum do={
        :set result ($result.$num)
    }

:put $result

Here’s one way I’m trying to make a function out of it.

:local number
:local reverseNumber do={
:local number
:local len [:len $number]
:local tmpNum [:toarray ""]
:local realNum [:toarray ""]
:local result

:local counter 0
while ( $counter<$len ) do={
    :set $tmpNum ($tmpNum, [:pick $number $counter ($counter+1)] )
    :set $counter ($counter + 1)
};

:local counter 0
while ( $counter<$len ) do={
    :if ( ($counter % 2) = 0) do={
        :set $realNum ($realNum, ($tmpNum->($counter+1) ) )
    } else={
        :set $realNum ($realNum, ($tmpNum->($counter-1) ) )
    }
  :set $counter ($counter + 1)
};

:put $realNum
:foreach num in=$realNum do={
        :set result ($result.$num)
    }

:return $result
}

:set $number "8350000048F0"
$reverseNumber $number

:local result [$reverseNumber $number]

Several problems. Main one is you need to use $1 to capture the 1st argument to the function and assign it to a “number” inside your function – no need for “:local number XXXX” if your using a function. Personally, I’d make the function itself global. Although you can keep it :local, but then entire block need to be enclosed in { } to keep the local function available to locals INSIDE same block (which is the 2nd problem since the local function is no longer available when you get to calling it… since not in same block).

So assuming we make the function a global, looks like this:


:global reverseNumber do={
    :local number [:tostr $1]
    :local len [:len $number]
    :local tmpNum [:toarray ""]
    :local realNum [:toarray ""]
    :local result

    :local counter 0
    while ( $counter<$len ) do={
        :set $tmpNum ($tmpNum, [:pick $number $counter ($counter+1)] )
        :set $counter ($counter + 1)
    };

    :local counter 0
    while ( $counter<$len ) do={
        :if ( ($counter % 2) = 0) do={
            :set $realNum ($realNum, ($tmpNum->($counter+1) ) )
        } else={
            :set $realNum ($realNum, ($tmpNum->($counter-1) ) )
        }
    :set $counter ($counter + 1)
    };

    :put $realNum
    :foreach num in=$realNum do={
            :set result ($result.$num)
        }

    :return $result
}

# test code for reverseNumber
{
:local numberarg "8350000048F0"
$reverseNumber $numberarg

:local result [$reverseNumber $numberarg]
:put $result
}

I left the “:put” inside the function, which may be for debugging. Also you might want to avoid using variable names that match commands, although that shouldn’t break anything here but not a good idea…

I think I’m beginning to understand. What if I want to use a named variable?

And another clarification, if I want to transfer the result of a function to an array, then I also have to use $result or can I write [$reverseNumber $numberarg] to the array right away?

Any named variable you provide, become a local to the function. No need to declare anything. So basically if you remove the first line of the function, you can just use “$reverseNumber number=ABCDEF”.

For completeness, you can make the function local, but then all code using it need to be in same block like:

{
    :local reverseNumber do={
        :local len [:len $number]
        :local tmpNum [:toarray ""]
        :local realNum [:toarray ""]
        :local result

        :local counter 0
        while ( $counter<$len ) do={
            :set $tmpNum ($tmpNum, [:pick $number $counter ($counter+1)] )
            :set $counter ($counter + 1)
        };

        :local counter 0
        while ( $counter<$len ) do={
            :if ( ($counter % 2) = 0) do={
                :set $realNum ($realNum, ($tmpNum->($counter+1) ) )
            } else={
                :set $realNum ($realNum, ($tmpNum->($counter-1) ) )
            }
        :set $counter ($counter + 1)
        };

        :put $realNum
        :foreach num in=$realNum do={
                :set result ($result.$num)
            }

        :return $result
    }


    {
    :local numberarg "8350000048F0"
    $reverseNumber number=$numberarg

    :local result [$reverseNumber number=$numberarg]
    :put $result
    }
}

Well, just skip the last part of your function and return $realNum (which is an array type). Or you can add a 2nd parameter that does takes “as-array” like so:


:global reverseNumber do={
        :local number $1
        :local len [:len $number]
        :local tmpNum [:toarray ""]
        :local realNum [:toarray ""]
        :local result

        :local counter 0
        while ( $counter<$len ) do={
            :set $tmpNum ($tmpNum, [:pick $number $counter ($counter+1)] )
            :set $counter ($counter + 1)
        };

        :local counter 0
        while ( $counter<$len ) do={
            :if ( ($counter % 2) = 0) do={
                :set $realNum ($realNum, ($tmpNum->($counter+1) ) )
            } else={
                :set $realNum ($realNum, ($tmpNum->($counter-1) ) )
            }
        :set $counter ($counter + 1)
        };

        :if ($2 = "as-array") do={
             :return $realNum
        } else={
            :foreach num in=$realNum do={
                :set result ($result.$num)
            }
            :return $result
        }
    }

For example,

{
:local rv [$reverseNumber ABCD as-array] 
:put $rv 
:put [:typeof $rv]
:set rv [$reverseNumber ABCD]
:put $rv 
:put [:typeof $rv]} 
}

# Output:
B;A;D;C
array
BADC
str

@DyadyaGenya
From question on this thread and http://forum.mikrotik.com/t/using-two-arrays-process-the-text-and-create-a-third-array/166923/1 are you aware of ROS script documentation existence? See: https://wiki.mikrotik.com/wiki/Manual:Scripting#Functions and https://help.mikrotik.com/docs/display/ROS/Scripting maybe it helps.

P.S.
You can use only local functions in script instead global, this complicates a bit calling them from another local functions, but you don’t need to unset them when your script finish if you don’t want leave them to hang in Environment. To call local function from other local function simply pass as argument variable, ex: [$funct1 funct2=$funct2], then you can call $funct2 inside $funct1 and you can go nested like that, function context must have nested local function variable passed from argument.

I watched them. They are very short and do not give a complete picture. If I had not looked at these instructions, I would not have been able to write the version of the code shown in the header. Luckily, Amm0 some things were explained to me.

Documentation doesn’t contain all possible examples of script features but you can get a clue what else can be possible to do depending on experience in development/scripting and some experimenting.

Sorry for this self-quotation, but my page is full of examples of how to code…

(please DO NOT post directly on the list, but in the various linked topics)
http://forum.mikrotik.com/t/rextended-fragments-of-snippets/151033/1

You have to divide the process into parts to do something useful, this also helps you to create functions…

Function to convert a PDU SMSCenter part to real number

Step 1) we have aldeady the length of the PDU, 48, and the PDU itself from this:
http://forum.mikrotik.com/t/using-two-arrays-process-the-text-and-create-a-third-array/166923/1
07912180958739F1040B917120069876F000009140503223218A21D4F29C0E6A97E7F3F0B90CA2BF41412A68F86EB7C36E32885A9ED3CB72
***** done *****

Step 2) check if the length and the PDU corresponding:
:local length ($item->“length”)
:local pdu ($item->“PDU”)
:local skip (2 + ([:tonum “0x$[:pick $pdu 0 2]”] * 2))
:if ($length = (([:len $pdu] - $skip) / 2)) do={:put “OK”} else={:put “KO”}
48 is the length of SMS part, that start just after the SMSCenter number, so must be skipped the first two and the length specified on first two…
07912180958739F1 040B917120069876F000009140503223218A21D4F29C0E6A97E7F3F0B90CA2BF41412A68F86EB7C36E32885A9ED3CB72

Working function:

{
:local SMScheckPDU do={
    :local length $1
    :local pdu    $2
    :local skip   (2 + ([:tonum "0x$[:pick $pdu 0 2]"] * 2))
    :if ($length = (([:len $pdu] - $skip) / 2)) do={:return "OK"} else={:return "KO"}
}

:put [$SMScheckPDU 48 07912180958739F1040B917120069876F000009140503223218A21D4F29C0E6A97E7F3F0B90CA2BF41412A68F86EB7C36E32885A9ED3CB72]
}

Step 3) pick only the smsc number part
{
:local pdu 07912180958739F1040B917120069876F000009140503223218A21D4F29C0E6A97E7F3F0B90CA2BF41412A68F86EB7C36E32885A9ED3CB72
:local rawSMSC [:pick $pdu 2 (2 + ([:tonum “0x$[:pick $pdu 0 2]”] * 2))]
:put $rawSMSC
}
912180958739F1

Working function

{
:local rawSMSC do={:return [:pick $1 2 (2 + ([:tonum "0x$[:pick $1 0 2]"] * 2))]}
:put [$rawSMSC 07912180958739F1040B917120069876F000009140503223218A21D4F29C0E6A97E7F3F0B90CA2BF41412A68F86EB7C36E32885A9ED3CB72]
}

Step 4a) Identify the type of number represented, to be developed later,
actually “91” is the international numbering format, so if is “91”, the number is on deci-decimal format to be reversed, and is starting with “+”
91 + and 2180958739F1

Step 4b) reverse the number
from + and 2180958739F1 to +12085978931
The F is just a pad character when the number of digits in the phone is odd.
Each pair of deci-decimal must be swapped for obtain the right number.
{
:local rawSMSC “2180958739F1”
:local lenSMSC [:len $rawSMSC]
:local currPos 0
:local smsc “”
:while (($lenSMSC + 1) > $currPos) do={
:set smsc “$smsc$[:pick $rawSMSC ($currPos + 1) ($currPos + 2)]$[:pick $rawSMSC $currPos ($currPos + 1)]”
:set currPos ($currPos + 2)
}
:put $smsc
}
now you have + and 12085978931F, what remains to be done is the next point (except the step 4a)


Step 5) Create a function that providing the raw SMSCenter value, provide correct number (except the step 4a, for now).
Working code:
{
:local SMSCfromPDU do={
:local pdu [:tostr $1]
:local length [:tonum “0$2”]
:local skip (2 + ([:tonum “0x$[:pick $pdu 0 2]”] * 2))
:if ($length > 0) do={
:if ($length != (([:len $pdu] - $skip) / 2)) do={:return “ERROR: Provided Length does not match SMS PDU part”}
}
:local smsc “”
:local type [:pick $pdu 2 4]
:if ($type = “91”) do={
:set smsc “+”
:local SMSCraw [:pick $pdu 4 $skip]
:local lenSMSC [:len $SMSCraw]
:local currPos 0
:while (($lenSMSC + 1) > $currPos) do={
:set smsc “$smsc$[:pick $SMSCraw ($currPos + 1) ($currPos + 2)]$[:pick $SMSCraw $currPos ($currPos + 1)]”
:set currPos ($currPos + 2)
}
:if ($smsc~“F$”) do={:set smsc [:pick $smsc 0 ([:len $smsc] - 1)]}
:return $smsc
}
:return “ERROR: Unexpected SMSC number type (0x$type)”
}

:put [$SMSCfromPDU 07912180958739F1040B917120069876F000009140503223218A21D4F29C0E6A97E7F3F0B90CA2BF41412A68F86EB7C36E32885A9ED3CB72 48]
}
The length is optional, if specified the validity of the PDU is calculated.

+1912085978931

To be honest, I did not think that this topic would turn into a topic for creating a number processing function in the SMS body. But good. you use the number 48. But I still do not understand why, if it is not used in all steps. Only at the very end, when you need to print the result.
And of course you have a simple and short function. But I deliberately did not post all the code in this thread, because I doubted some of the data, such as encrypting the length of the number. But in general, my function also easily turns an encrypted number from SMS into a regular one. We use different algorithms. I try to work more with arrays. I am learning to work with arrays. I don't know which way is better. Surely each method has its own merits.

And I'm wondering what is "KO" in your code?

FYI https://www.geeksforgeeks.org/difference-between-encryption-and-encoding/

For me you have serious problems of understanding...
Do one thing at a time, you're just messing around...
Where do you think 48 (decimal) comes from?

+CMGL: 0,1,,48\r\n07912180958739F1040B917120069876F0000091405[…]0E6A97E7F3F0B90CA2BF41412A68F86EB7C36E32885A9ED3CB72

You still haven't figured out what the individual values are for and you keep talking about encrypted text messages...


Doing multiple loops, using arrays, and calculating odd/even again is just a waste of time.
Nothing is perfect, but for decrypting the SMSCenter mine is better,
instead of using a loop to convert single characters into an array of characters, then do another loop where you put two tests, if the number is even or the number is odd, etc...


Seriously? Where do you live? I understand the language issues, but maybe in your country "KO" is not the opposite of "OK"....



If all this is reduced to using loops and even and odd checks that make no sense, just to practice (unnecessarily and in the wrong way) with arrays I'm not going to help you anymore.
Here on the forum I write code for everyone, and having to cripple a procedure just to use the arrays unnecessarily, I don't teach the others anything, and you don't want to learn.

I understand now. Thank you. Only now I don’t understand why, after I started working at the beginning of the garden, I need to run to the end of the garden, if in the end I need to plow the entire garden. Perhaps I did not understand your algorithm, but at the moment it looks like this. At the same time, we have almost all the data to do the work gradually step by step from the beginning of the garden.

we almost never use this word. Only those who work with tourists and some programmers. The rest, if they are told "OK", can answer "Ob". This is the name of the manufacturer of feminine hygiene products. And since I'm not exactly a programmer, I'm not very familiar with the terms and accepted abbreviations. There were thoughts that "KO" is an abbreviation for "Company".

Again, in this situation, I just learned to write a function. An additional condition was the desire to do it using arrays. But this desire is not necessary.
In this case, your method only works with 12-digit numbers. My method is not so strictly limited. It can process both a number with more characters and a number with fewer characters. I mean, it's more versatile.
I feel embarrassed in this debate, because you have done a lot for this society, and I am only a beginner. But sometimes the older ones should help the younger ones not in everything, but only in what the younger ones ask, and not do all the work instead of them. Otherwise, neither these juniors, nor others who will follow them, will learn anything new, but will only know what you know.

What would be the function limited to 12 characters only?

Phone translation. We don't know what other numbers are. You voiced some yesterday in another topic, but I have not had time to deal with them yet.

But you didn't explain why the function should be work only with 12 telephone digits

I apologize for the confusion. In your case, the length of the phone number can vary, and the current implementation of the function only works with 12-digit numbers. If you need to handle phone numbers of different lengths, you can modify the function to accommodate them. You may need to adjust the logic and consider the specific requirements for handling shorter or longer phone numbers.

But where is it written in the function that accepts only 12 numbers?
You keep insisting, but there is no logic in what you write…

I don't know who doesn't understand whom and why. Maybe even chatGPT can't handle the translation. Let's point by point. Short messages. I'm talking about your version of the function. It's clear?