Summary:ASTERISK-03556: [patch] $(func "arg" xyz) expression in dialplan
Reporter:Anthony Minessale (anthm)Labels:
Date Opened:2005-02-21 12:50:17.000-0600Date Closed:2008-01-15 15:26:54.000-0600
Versions:Frequency of
Environment:Attachments:( 0) dollar_func_rev0.diff
( 1) dollar_func_rev1.diff
( 2) dollar_func_rev2.diff
( 3) dollar_func_rev3.diff
( 4) dollar_func_rev4.diff
( 5) dollar_func_rev5.diff
( 6) dollar_func_rev6.diff
( 7) dollar_func_rev7.diff.txt
( 8) res_function_demo.c
Description:This patch adds a new parsable entity to the dialplan to perform certian precompiled functions

the current functions all return 0 and 1 for true/false:
isnull: the string is null
exists: the opposite of isnull
contains: the string contains a certian substring
begins: the string begins with a certian substring
ends: the string ends with a certian substring
regex: the string contains the certian regex


exten => 1,1,GotoIf($(isnull ${MYVAR})?2:3)
exten => 1,1,GotoIf($(contains "foo" ${MYVAR})?2:3)
exten => 1,1,GotoIf($(regex "a.*" ${MYVAR})?2:3)


Disclaimer on file
Comments:By: Kevin P. Fleming (kpfleming) 2005-02-21 13:06:55.000-0600

Is there a specific reason why "arg" has to be in quotes but xyz does not? What if the value of MYVAR in the examples above contained whitespace?

IMO, I think you should split up the arguments on whitespace (allowing more than two arguments if needed) and allow quotes to override that splitting.

Will it be possible for this function evaluation to return a string value in the future? I have plans for something that needs that :-)

By: Kevin P. Fleming (kpfleming) 2005-02-21 13:13:11.000-0600

Also, you can use ast_trim instead of lose_leading_spaces, that will remove trailing whitespace as well.

I see now that you've built this to handle string return values... cool.

Instead of using strdup(true) and strdup(false) all those times, why not just malloc() a 2-character string, set the character to '1' or '0' as needed, and return the string pointer? Once you have determined that you have a valid operation name, you know for sure that you're going to be returning a result.

By: Anthony Minessale (anthm) 2005-02-21 14:09:23.000-0600

After closer consideration I have changed it to only permit 1 space to seperate which will be required so it works as follows


Where argument is only valid when called for by the prototype

In this example the 2 spaces are required.  Everything from where the ${VAR} starts to the final ) is the boundry of the evaluation string
$(regex "f.*o" ${VAR})

here "foo" is isolated because it starts after exactly 1 space and ends before the )
$(begins foo)

I don't want to support multiple arguements because there is nothing that needs it and mark seemed pretty strict about implementing stuff before you need it.

If you did want to though you could delimit the contents of "" with another delim in the handler for that paticular multiarg func

$(future "a|b|c" ${VAR})
$(future "'a a','b b','c c'" ${VAR})

That would let you be a bit flexable with what to do with the data.

By: Anthony Minessale (anthm) 2005-02-21 14:11:43.000-0600

oh yeah the strdups, it seems like just as much work to malloc in every "if" *shrug* maybe it's not I'm kind burned out on this one for now.

By: Kevin P. Fleming (kpfleming) 2005-02-21 22:16:35.000-0600

I didn't mean to malloc() in every if, I meant to malloc() before going into the if's as soon as you know you've got an operation to do. Each operation can then set the value of the string (without returning), and then final step would just return the string pointer.

By: Mark Spencer (markster) 2005-02-22 00:05:21.000-0600

Fantastic idea.  Does this belong more in $[] than $() ? just something to consider, no strong preconceived feelings one way or another.

By: Anthony Minessale (anthm) 2005-02-22 16:10:38.000-0600

I whole heartedly believe it belongs in it's own $(func )

But wait!.... there's more!, in today's release you can, you guessed it, create and load your own custom functions that recieve the inner data and allow you to parse it anyway you want and returned a malloc'd string of your choice, or NULL if you want. This is, of course, only attempted on an unknown function name and the code is terse and ready to be upgraded to hash as soon as we have one =)

See attached example res_function_demo.c

By: Kevin P. Fleming (kpfleming) 2005-02-22 16:16:33.000-0600

Nice work... the function executer still has some little nits, like trying to strdup ret when it's NULL, but I'm sure you can find those :-)

Any reason to hardcode the builtin functions, rather than creating structures and registering them all? It would be more overhead I'm sure, but more logical (the same way we do builtins, CLI commands, etc).

By: Anthony Minessale (anthm) 2005-02-22 17:39:14.000-0600

k, end to strdup null.

They could all be registered but i'm not sure how efficient it is atm
to do a gazillion list walks and or how it compares to a gazillion strcmps,  I'd like to setup an opmtized way to figure out the func HASH still comming?

I'm also tempted to pass chan to the functions but i'm on the fence on that one it's right there to pass but it may be out of the scope of what I'm trying to do.

By: Kevin P. Fleming (kpfleming) 2005-02-22 17:51:56.000-0600

Yeah, I considered passing chan as well when I was thinking about this, but I think it's a bad idea. I'd rather just tell people that if they want to pass in channel variables, they can pass as many as they want and be done with it.

Yes, hash tables are still in the works, but are pending the work that oej is doing in chan_sip (it's too much of a moving target right now). I am debating whether to just post a patch that converts the dialplan over to ASTOBJ, but haven't made up my mind.

By: Anthony Minessale (anthm) 2005-02-22 18:16:52.000-0600

How bout this?

I'm tryin it on for size registering the internals and I decided, "Hey regex is powerful enough to obselete begins, ends and contains" so i just did regex.

That also lets you "show functions" and see the regex and keeps ppl from using the name in thier module.

I'm also testing out the idea of passing chan, you don't *have* to use it but you may want it for some creative application down the road it's just sitting there to be passed anyway but i'm still not sure about it.

What I'm envisioning is stuff like app_queue registering queuecount where you can say like

exten => 1,1,GotoIf($[ $(queuecount sales) > 1 ]?2:3)

and much more in all kinds of modules.

edited on: 02-22-05 18:19

By: Kevin P. Fleming (kpfleming) 2005-02-22 18:32:24.000-0600

Right, that's a perfect example of the things this will be useful for. I am scared of passing "chan", though, then you get into locking issues and other crap that these very simple functions should probably not have to deal with.

By: Anthony Minessale (anthm) 2005-02-22 18:40:46.000-0600

yah ok, I can't do it.  chan .... you're fired!

repealed rev4 and reposted w/o chan.

I included the cmd as a sort of argv[0] in case you use the same core func for mutiple commands or you want to say ast_verbose("I am %s\n", cmd) wo worrying about the name.

edited on: 02-22-05 18:44

By: Tilghman Lesher (tilghman) 2005-02-23 08:53:59.000-0600

This is very similar in functionality to ASTERISK-2248

By: Anthony Minessale (anthm) 2005-02-24 09:47:17.000-0600

rev5 no changes just keep clean patch with cvs

By: Anthony Minessale (anthm) 2005-02-25 09:05:19.000-0600

yet another rev to keep up with pbx.c.

By: Mark Spencer (markster) 2005-02-26 01:02:16.000-0600

Do you envision these as being settable too or just gettable?

By: Anthony Minessale (anthm) 2005-02-26 09:16:22.000-0600

I suppose they are bi-directional since they take can take input (anything between 1 space after the func name and the terminating ')' ) if the function is registered from say chan_sip it's welcome to maintain a private namespace and keep track of certian inputted values.  It also passes the func name to the internal func so you can register the same 1 fucntion to mutiple commands if you want and test the cmd str to see which one is being called.

Setting AND Getting whould be Something like:

** not intended to necessarily be used just an example so put you flame throwers down. =D **
$(SIPset someSIPvar=someSIPval)
$(SIPget someSIPvar)

Here are some more nifty "possible" usages.

$(DundiLookupRoute ${EXTEN})
$(SIPisRegistered somepeer)
$(SQLite select dest from routing where exten='${EXTEN}')
$(ZapHasFreeChans g10)

By: Mark Spencer (markster) 2005-03-03 17:53:07.000-0600

Rather than strdup, how about we pass workspace?

By: Brian West (bkw918) 2005-03-03 20:14:15.000-0600

rev7 uploaded as per tony's request.. his laptop died before he could upload it.


By: Mark Spencer (markster) 2005-03-04 00:39:14.000-0600

Added to CVS with small modifications (mainly docs)

By: Digium Subversion (svnbot) 2008-01-15 15:26:54.000-0600

Repository: asterisk
Revision: 5136

U   trunk/doc/README.variables
U   trunk/include/asterisk/pbx.h
U   trunk/pbx.c

r5136 | markster | 2008-01-15 15:26:53 -0600 (Tue, 15 Jan 2008) | 2 lines

Add registerable functional variables (bug ASTERISK-3556, with doc mods)