From 29502d3bac9ed4e5893d8c0cf1027d211ab26d26 Mon Sep 17 00:00:00 2001
From: Tilghman Lesher <tilghman@meg.abyt.es>
Date: Tue, 2 Dec 2008 18:39:12 +0000
Subject: [PATCH] Add LOCAL_PEEK function, as requested by lmadsen.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@160344 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 apps/app_stack.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/apps/app_stack.c b/apps/app_stack.c
index 0a911e5ecf..1311bad77c 100644
--- a/apps/app_stack.c
+++ b/apps/app_stack.c
@@ -142,6 +142,27 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 			<ref type="application">Return</ref>
 		</see-also>
 	</function>
+	<function name="LOCAL_PEEK" language="en_US">
+		<synopsis>
+			Retrieve variables hidden by the local gosub stack frame.
+		</synopsis>
+		<syntax>
+			<parameter name="n" required="true" />
+			<parameter name="varname" required="true" />
+		</syntax>
+		<description>
+			<para>Read a variable <replaceable>varname</replaceable> hidden by 
+			<replaceable>n</replaceable> levels of gosub stack frames.  Note that ${LOCAL_PEEK(0,foo)}
+			is the same as ${foo}, since the value of <replaceable>n</replaceable> peeks under 0 levels of
+			stack frames; in other words, 0 is the current level.  If <replaceable>n</replaceable> exceeds
+			the available number of stack frames, then an empty string is returned.</para>
+		</description>
+		<see-also>
+			<ref type="application">Gosub</ref>
+			<ref type="application">GosubIf</ref>
+			<ref type="application">Return</ref>
+		</see-also>
+	</function>
  ***/
 
 static const char *app_gosub = "Gosub";
@@ -471,6 +492,42 @@ static struct ast_custom_function local_function = {
 	.read = local_read,
 };
 
+static int peek_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
+{
+	int found = 0, n;
+	struct ast_var_t *variables;
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(n);
+		AST_APP_ARG(name);
+	);
+
+	if (!chan) {
+		ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n");
+		return -1;
+	}
+
+	AST_STANDARD_APP_ARGS(args, data);
+	n = atoi(args.n);
+	*buf = '\0';
+
+	ast_channel_lock(chan);
+	AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
+		if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) {
+			ast_copy_string(buf, ast_var_value(variables), len);
+			break;
+		}
+	}
+	ast_channel_unlock(chan);
+	return 0;
+}
+
+static struct ast_custom_function peek_function = {
+	.name = "LOCAL_PEEK",
+	.synopsis = "Peeks at variables within the variable stack",
+	.syntax = "LOCAL_PEEK(<n>|<varname>)",
+	.read = peek_read,
+};
+
 static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, char **argv)
 {
 	int old_priority, priority;
@@ -585,6 +642,7 @@ static int unload_module(void)
 	ast_unregister_application(app_gosubif);
 	ast_unregister_application(app_gosub);
 	ast_custom_function_unregister(&local_function);
+	ast_custom_function_unregister(&peek_function);
 
 	return 0;
 }
@@ -607,6 +665,7 @@ static int load_module(void)
 	ast_register_application_xml(app_gosubif, gosubif_exec);
 	ast_register_application_xml(app_gosub, gosub_exec);
 	ast_custom_function_register(&local_function);
+	ast_custom_function_register(&peek_function);
 
 	return 0;
 }
-- 
GitLab