Summary:ASTERISK-00360: [patch] app_cut
Reporter:John Todd (jtodd)Labels:
Date Opened:2003-10-07 14:12:18Date Closed:2004-09-25 02:21:16
Versions:Frequency of
Environment:Attachments:( 0) app_cut.c
( 1) app_cut.c
( 2) app_cut.c
( 3) app_cut.c
Description:Tilghman's app_cut.c, as sent out on the mailing list.  I don't see it here, so I figure I'll put it forward to make sure it doesn't get lost.  


* Asterisk -- A telephony toolkit for Linux.
* Cut application
* Copyright (c) 2003 Tilghman Lesher.  All rights reserved.
* Tilghman Lesher <app_cut__200310@the-tilghman.com>
* This code is released by the author with no restrictions on usage.

#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

static char *tdesc = "Cuts up variables";

static char *app_cut = "Cut";

static char *cut_synopsis = "Cut(newvar=varname|delimiter|field)";

static char *cut_descrip =
"  newvar    - result string is set to this variable\n"
"  varname   - variable you want cut\n"
"  delimiter - defaults to -\n"
"  field     - number of the field you want (1-based offset)\n"
"  Returns 0 or -1 on hangup or error.\n";



static int cut_exec(struct ast_channel *chan, void *data)
int res=0;
struct localuser *u;
char *s, *newvar, *varname, *delimiter, *field;
int fieldnum, args_okay = 0;


/* Check and parse arguments */
if (data) {
s = strdupa((char *)data);
if (s) {
newvar = strsep(&s, "=");
if (newvar && (newvar[0] != '\0')) {
varname = strsep(&s, "|");
if (varname && (varname[0] != '\0')) {
delimiter = strsep(&s, "|");
if (delimiter) {
field = strsep(&s, "|");
if (field && (sscanf(field,"%d",&fieldnum) == 1)) {
args_okay = 1;
} else {
ast_log(LOG_ERROR, "Out of memory\n");
res = -1;

if (args_okay) {
char d;
char *tmp;

if (delimiter[0])
d = delimiter[0];
d = '-';

tmp = pbx_builtin_getvar_helper(chan, varname);
if (tmp) {
tmp = strdupa(tmp);
if (tmp) {
int i;
for (i=1;i<fieldnum;i++)
if (tmp && (tmp[0] != '\0'))
tmp = index(tmp, d) + 1;
} else {
ast_log(LOG_ERROR, "Out of memory\n");
res = -1;
if (tmp) {
/* Get end, if any */
/* (if no further fields, then tmp -> NULL, but we don't care anymore) */
char *value = strsep(&tmp, &d);
pbx_builtin_setvar_helper(chan, newvar, value);
} else {
ast_log(LOG_ERROR, "Usage: %s\n", cut_synopsis);
res = -1;

return res;

int unload_module(void)
return ast_unregister_application(app_cut);

int load_module(void)
return ast_register_application(app_cut, cut_exec, cut_synopsis, cut_descrip);

char *description(void)
return tdesc;

int usecount(void)
int res;
return res;

char *key()

Comments:By: John Todd (jtodd) 2003-10-07 17:19:17

Alas, this does not seem to work, though it an optimally designed tool for processing what I hope will be the eventual transmission of SIP URIs in their "native" state to the dialplan.  I tried with delimiters other than "@" and with diferent strings, to no avail.

exten => _.,1,Cut(BAR=bob@nowhere.com|@|1)
exten => _.,2,NoOp(${BAR})

   -- Executing Cut("SIP/2203-c027", "BAR=bob@nowhere.com|@|1") in new stack
   -- Executing NoOp("SIP/2203-c027", "") in new stack

By: Tilghman Lesher (tilghman) 2003-10-07 20:39:24

Unfortunately, your usage will not work.  I wrote this with the idea that a variable value might have a ',' or a '|' embedded, screwing up the parsing of the rest of the arguments, so here's how you use this:

exten => 3,1,Cut(mychan=CHANNEL,,1)
exten => 3,2,NoOp(${mychan})

or, for your example:

exten => 3,1,SetVar(email=bob@nowhere.com)
exten => 3,2,Cut(name=email,@,1)
exten => 3,3,NoOp(${name})

I know that's an extra step, but I think the reason for doing this is well worth the extra effort.

By: John Todd (jtodd) 2003-10-07 21:54:26

OK, the syntax still throws me a bit (the absence of ${} around "name" in your example) but it does work as shown, and I understand the reasoning for it being like that.   Thanks!

By: Tilghman Lesher (tilghman) 2003-10-10 02:10:25

Second version just uploaded; now includes the ability to specify more than one field, just like the cut(1) Unix application.  Instead of using the , (comma) to separate groups of fields, however, app_cut uses & (ampersand) to separate groups of fields.

Also supports ranges and the ability to leave off an end to a range, e.g. 2- means all fields after the first, and -2 means the first two fields.

By: John Todd (jtodd) 2003-10-19 20:00:13

Tested, and has worked fine for several days with different iterations.

By: Mark Spencer (markster) 2003-10-21 22:17:22

app_cut.c: In function `cut_exec':
app_cut.c:134: warning: comparison between pointer and integer
app_cut.c:146: warning: comparison between pointer and integer
app_cut.c:54: warning: `newvar' might be used uninitialized in this function
app_cut.c:54: warning: `varname' might be used uninitialized in this function
app_cut.c:54: warning: `delimiter' might be used uninitialized in this function gcc -shared -Xlinker -x -o app_cut.so app_cut.o

These need to be resolved first.

By: Tilghman Lesher (tilghman) 2003-10-21 23:05:41

Requested changes made.

By: Mark Spencer (markster) 2003-10-22 08:09:10

Added to CVS