Add media control commands. Add possibility to invoke media control commands by detected tone events in real time
parent
eeff524567
commit
c2411cac82
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,344 @@
|
||||
/*
|
||||
*
|
||||
Copyright (c) Dialogic, 2009.
|
||||
*
|
||||
This source file is supplied for the use with
|
||||
Dialogic range of DIVA Server Adapters.
|
||||
*
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
*
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
*
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include <sys/time.h>
|
||||
#include <sys/signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "xlaw.h"
|
||||
#include "chan_capi20.h"
|
||||
#include "chan_capi.h"
|
||||
#include "chan_capi_rtp.h"
|
||||
#include "chan_capi_qsig.h"
|
||||
#include "chan_capi_qsig_ecma.h"
|
||||
#include "chan_capi_qsig_asn197ade.h"
|
||||
#include "chan_capi_qsig_asn197no.h"
|
||||
#include "chan_capi_utils.h"
|
||||
#include "chan_capi_supplementary.h"
|
||||
#include "chan_capi_chat.h"
|
||||
#include "chan_capi_command.h"
|
||||
|
||||
typedef struct _pbx_capi_voice_command {
|
||||
diva_entity_link_t link;
|
||||
pbx_capi_command_proc_t pbx_capi_command;
|
||||
char channel_command_digits[AST_MAX_EXTENSION+1];
|
||||
int length; /* channel_command_digits length */
|
||||
char command_name[64];
|
||||
char command_parameters[128];
|
||||
} pbx_capi_voice_command_t;
|
||||
|
||||
/*
|
||||
* LOCALS
|
||||
*/
|
||||
static const char* pbx_capi_voicecommand_digits = "1234567890ABCD*#";
|
||||
static int pbx_capi_command_nop (struct ast_channel *c, char *param);
|
||||
static pbx_capi_voice_command_t* pbx_capi_find_command (struct ast_channel *c, const char* name);
|
||||
static pbx_capi_voice_command_t* pbx_capi_find_command_by_key (struct ast_channel *c, const char* key);
|
||||
static pbx_capi_voice_command_t* pbx_capi_voicecommand_find_digit_command (diva_entity_queue_t* q, const char* digits, int length, int* info);
|
||||
static void pbx_capi_voicecommand_insert_command (diva_entity_queue_t* q, pbx_capi_voice_command_t* cmd);
|
||||
|
||||
|
||||
/*
|
||||
* voicecommand|key|param1|param2|...
|
||||
*
|
||||
*/
|
||||
int pbx_capi_voicecommand (struct ast_channel *c, char *param) {
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
pbx_capi_voice_command_t* cmd;
|
||||
const char* command[2];
|
||||
const char* key[2];
|
||||
size_t length;
|
||||
|
||||
if (param == 0 || *param == 0) { /* Remove all voice commands */
|
||||
cc_mutex_lock(&i->lock);
|
||||
pbx_capi_voicecommand_cleanup (i);
|
||||
cc_mutex_unlock(&i->lock);
|
||||
return (0);
|
||||
}
|
||||
|
||||
command[0] = param;
|
||||
command[1] = strchr (command[0], '|');
|
||||
|
||||
if (command[1] == 0) {
|
||||
/*
|
||||
* Remove command
|
||||
*/
|
||||
cc_mutex_lock(&i->lock);
|
||||
while ((cmd = pbx_capi_find_command (c, command[0])) != 0) {
|
||||
cc_verbose(2, 0, VERBOSE_PREFIX_4"%s: voicecommand:%s removed\n", i->vname, cmd->command_name);
|
||||
diva_q_remove (&i->channel_command_q, &cmd->link);
|
||||
free (cmd);
|
||||
}
|
||||
cc_mutex_unlock(&i->lock);
|
||||
} else {
|
||||
if ((command[1] - command[0]) < 2 || (command[1] - command[0]) >= sizeof(cmd->command_name) ||
|
||||
strchr(pbx_capi_voicecommand_digits, command[1][1]) == 0) {
|
||||
cc_log(LOG_WARNING, CC_MESSAGE_NAME" voicecommand requires an argument im format 'voicecommand[|key[|param1|param2|...]]'\n");
|
||||
return (-1);
|
||||
}
|
||||
key[0] = &command[1][1];
|
||||
key[1] = strchr (key[0], '|');
|
||||
length = 0;
|
||||
if ((key[1] == 0 && strlen(key[0]) >= sizeof(cmd->channel_command_digits)) ||
|
||||
(key[1] != 0 && ((key[1] - key[0]) == 0 || (key[1] - key[0]) >= sizeof(cmd->channel_command_digits) ||
|
||||
key[1][1] == 0 || (length = strlen (&key[1][1])) >= sizeof(cmd->command_parameters)))) {
|
||||
|
||||
cc_log(LOG_WARNING, CC_MESSAGE_NAME
|
||||
" voicecommand requires an argument im format 'voicecommand[|key[|param1|param2|...]]'\n");
|
||||
return (-1);
|
||||
}
|
||||
if (key[1] == 0) {
|
||||
key[1] = key[0] + strlen(key[0]);
|
||||
length = 0;
|
||||
}
|
||||
|
||||
{
|
||||
const char* p = key[0];
|
||||
|
||||
for (p = key[0]; p < key[1]; p++) {
|
||||
if (strchr(pbx_capi_voicecommand_digits, *p) == 0) {
|
||||
cc_log(LOG_WARNING, CC_MESSAGE_NAME
|
||||
" voicecommand key can use only '%s'\n", pbx_capi_voicecommand_digits);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmd = malloc (sizeof(*cmd));
|
||||
if (cmd == 0) {
|
||||
cc_log(LOG_WARNING, CC_MESSAGE_NAME " can not allocate memory for voice command\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memcpy (cmd->command_parameters, &key[1][1], length);
|
||||
cmd->command_parameters[length] = 0;
|
||||
|
||||
length = command[1] - command[0];
|
||||
memcpy (cmd->command_name, command[0], length);
|
||||
cmd->command_name[length] = 0;
|
||||
|
||||
length = key[1] - key[0];
|
||||
memcpy (cmd->channel_command_digits, key[0], length);
|
||||
cmd->channel_command_digits[length] = 0;
|
||||
cmd->length = length;
|
||||
|
||||
cmd->pbx_capi_command = pbx_capi_lockup_command_by_name (cmd->command_name);
|
||||
if ( cmd->pbx_capi_command == 0) {
|
||||
cmd->pbx_capi_command = pbx_capi_command_nop; /* accept unknown commands for compatibility reason */
|
||||
}
|
||||
|
||||
|
||||
cc_verbose(2, 0, VERBOSE_PREFIX_4 "%s: %svoicecommand:%s|%s|%s\n",
|
||||
i->vname, (cmd->pbx_capi_command == pbx_capi_command_nop) ? "dummy " : "",
|
||||
cmd->command_name, cmd->channel_command_digits, cmd->command_parameters);
|
||||
|
||||
{
|
||||
pbx_capi_voice_command_t* present_cmd;
|
||||
|
||||
cc_mutex_lock(&i->lock);
|
||||
if ((present_cmd = pbx_capi_find_command_by_key (c, cmd->command_name)) != 0) {
|
||||
diva_q_remove (&i->channel_command_q, &present_cmd->link);
|
||||
}
|
||||
pbx_capi_voicecommand_insert_command (&i->channel_command_q, cmd);
|
||||
cc_mutex_unlock(&i->lock);
|
||||
|
||||
if (present_cmd != 0) {
|
||||
free (present_cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int pbx_capi_voicecommand_transparency (struct ast_channel *c, char *param) {
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
|
||||
if (param == 0 || *param == 0) {
|
||||
cc_log(LOG_WARNING, "Parameter for voicecommand transparency missing.\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (ast_true(param)) {
|
||||
i->command_pass_digits = 1;
|
||||
} else if (ast_false(param)) {
|
||||
i->command_pass_digits = 0;
|
||||
} else {
|
||||
cc_log(LOG_WARNING, "Wrong parameter for voicecommand transparency.\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int pbx_capi_voicecommand_cleanup (struct capi_pvt *i) {
|
||||
diva_entity_link_t* link;
|
||||
|
||||
while ((link = diva_q_get_head (&i->channel_command_q)) != 0) {
|
||||
diva_q_remove (&i->channel_command_q, link);
|
||||
free (link);
|
||||
}
|
||||
|
||||
i->channel_command_digit = 0;
|
||||
i->channel_command_timestamp = 0;
|
||||
i->command_pass_digits = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static pbx_capi_voice_command_t* pbx_capi_find_command (struct ast_channel *c, const char* name) {
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
diva_entity_link_t* link;
|
||||
|
||||
for (link = diva_q_get_head (&i->channel_command_q); link != 0; link = diva_q_get_next (link)) {
|
||||
if (strcmp (((pbx_capi_voice_command_t*)link)->command_name, name) == 0) {
|
||||
return ((pbx_capi_voice_command_t*)link);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static pbx_capi_voice_command_t* pbx_capi_find_command_by_key (struct ast_channel *c, const char* key) {
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
diva_entity_link_t* link;
|
||||
|
||||
for (link = diva_q_get_head (&i->channel_command_q); link != 0; link = diva_q_get_next (link)) {
|
||||
if (strcmp (((pbx_capi_voice_command_t*)link)->channel_command_digits, key) == 0) {
|
||||
return ((pbx_capi_voice_command_t*)link);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process received DTMF digit
|
||||
*
|
||||
* returs zero if digit should be processed as usually
|
||||
* returns -1 if digit should be discarded
|
||||
*/
|
||||
int pbx_capi_voicecommand_process_digit (struct capi_pvt *i, char digit) {
|
||||
struct ast_channel *c = i->owner;
|
||||
pbx_capi_voice_command_t* cmd;
|
||||
int info;
|
||||
time_t t;
|
||||
|
||||
/*
|
||||
Simple algorithm due to low amount of entries, moreover all sequences will be short, only 1 ... 2 digits
|
||||
*/
|
||||
if (c == 0 || diva_q_get_head (&i->channel_command_q) == 0 ||
|
||||
strchr (pbx_capi_voicecommand_digits, digit) == 0) {
|
||||
i->channel_command_digit = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
t = time(0);
|
||||
if ((i->channel_command_digit != 0 && difftime (t, i->channel_command_timestamp) > 2) ||
|
||||
i->channel_command_digit >= (sizeof(i->channel_command_digits) - 1)) {
|
||||
i->channel_command_digit = 0;
|
||||
}
|
||||
|
||||
i->channel_command_timestamp = t;
|
||||
|
||||
i->channel_command_digits[i->channel_command_digit++] = digit;
|
||||
i->channel_command_digits[i->channel_command_digit] = 0;
|
||||
cmd = pbx_capi_voicecommand_find_digit_command (&i->channel_command_q,
|
||||
i->channel_command_digits,
|
||||
i->channel_command_digit,
|
||||
&info);
|
||||
if (cmd != 0) {
|
||||
char command_parameters_copy[sizeof( cmd->command_parameters)];
|
||||
|
||||
i->channel_command_digit = 0;
|
||||
|
||||
cc_verbose(2, 0, VERBOSE_PREFIX_4 "%s: call voicecommand:%s|%s|%s\n",
|
||||
i->vname, cmd->command_name, cmd->channel_command_digits, cmd->command_parameters);
|
||||
|
||||
strcpy (command_parameters_copy, cmd->command_parameters);
|
||||
info = ((*(cmd->pbx_capi_command))(c, command_parameters_copy));
|
||||
|
||||
cc_verbose(2, 0, VERBOSE_PREFIX_4 "%s: voicecommand:%s|%s|%s %s\n",
|
||||
i->vname, cmd->command_name, cmd->channel_command_digits, cmd->command_parameters, info == 0 ? "OK" : "ERROR");
|
||||
|
||||
} else if (info == 0) {
|
||||
i->channel_command_digit = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
return ((i->command_pass_digits != 0) ? 0 : -1);
|
||||
}
|
||||
|
||||
static pbx_capi_voice_command_t* pbx_capi_voicecommand_find_digit_command (diva_entity_queue_t* q,
|
||||
const char* digits,
|
||||
int length,
|
||||
int* info) {
|
||||
diva_entity_link_t* link;
|
||||
|
||||
for (*info = 0, link = diva_q_get_head (q);
|
||||
link != 0 && length <= ((pbx_capi_voice_command_t*)link)->length;
|
||||
link = diva_q_get_next (link)) {
|
||||
pbx_capi_voice_command_t* cmd = (pbx_capi_voice_command_t*)link;
|
||||
|
||||
cc_verbose(2, 0, VERBOSE_PREFIX_4 "check digit: %s to %s\n", digits, cmd->channel_command_digits);
|
||||
|
||||
if (memcmp (digits, cmd->channel_command_digits, length) == 0) {
|
||||
*info = 1;
|
||||
if (length == cmd->length) {
|
||||
return (cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int pbx_capi_command_nop (struct ast_channel *c, char *param) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void pbx_capi_voicecommand_insert_command (diva_entity_queue_t* q, pbx_capi_voice_command_t* cmd) {
|
||||
diva_entity_link_t* link;
|
||||
|
||||
for (link = diva_q_get_head (q); link != 0; link = diva_q_get_next (link)) {
|
||||
if (((pbx_capi_voice_command_t*)link)->length <= cmd->length) {
|
||||
diva_q_insert_before (q, link, &cmd->link);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
diva_q_add_tail (q, &cmd->link);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* vim:ts=2
|
||||
*/
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
*
|
||||
Copyright (c) Dialogic, 2009.
|
||||
*
|
||||
This source file is supplied for the use with
|
||||
Dialogic range of DIVA Server Adapters.
|
||||
*
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
*
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
*
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef __CHAN_CAPI_COMMAND_H__
|
||||
#define __CHAN_CAPI_COMMAND_H__
|
||||
|
||||
int pbx_capi_voicecommand (struct ast_channel *c, char *param);
|
||||
int pbx_capi_voicecommand_transparency (struct ast_channel *c, char *param);
|
||||
int pbx_capi_voicecommand_process_digit (struct capi_pvt *i, char digit);
|
||||
int pbx_capi_voicecommand_cleanup (struct capi_pvt *i);
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,167 @@
|
||||
/*
|
||||
*
|
||||
Copyright (c) Dialogic, 2009.
|
||||
*
|
||||
This source file is supplied for the use with
|
||||
Dialogic range of DIVA Server Adapters.
|
||||
*
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
*
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
*
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#include "dlist.h"
|
||||
|
||||
/*
|
||||
** Initialize linked list
|
||||
*/
|
||||
|
||||
void
|
||||
diva_q_init (diva_entity_queue_t* q)
|
||||
{
|
||||
q->head = q->tail = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove element from linked list
|
||||
*/
|
||||
void
|
||||
diva_q_remove (diva_entity_queue_t* q, diva_entity_link_t* what)
|
||||
{
|
||||
if(!what->prev) {
|
||||
if ((q->head = what->next)) {
|
||||
q->head->prev = 0;
|
||||
} else {
|
||||
q->tail = 0;
|
||||
}
|
||||
} else if (!what->next) {
|
||||
q->tail = what->prev;
|
||||
q->tail->next = 0;
|
||||
} else {
|
||||
what->prev->next = what->next;
|
||||
what->next->prev = what->prev;
|
||||
}
|
||||
what->prev = what->next = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add element to the tail of linked list
|
||||
*/
|
||||
void
|
||||
diva_q_add_tail (diva_entity_queue_t* q, diva_entity_link_t* what)
|
||||
{
|
||||
what->next = 0;
|
||||
if (!q->head) {
|
||||
what->prev = 0;
|
||||
q->head = q->tail = what;
|
||||
} else {
|
||||
what->prev = q->tail;
|
||||
q->tail->next = what;
|
||||
q->tail = what;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Add element to the linked list after a specified element
|
||||
*/
|
||||
void diva_q_insert_after (diva_entity_queue_t* q, diva_entity_link_t* prev, diva_entity_link_t* what)
|
||||
{
|
||||
diva_entity_link_t *next;
|
||||
|
||||
if((0 == prev) || (0 == (next=diva_q_get_next(prev)))){
|
||||
diva_q_add_tail(q,what);
|
||||
return;
|
||||
}
|
||||
what->prev = prev;
|
||||
what->next = next;
|
||||
prev->next = what;
|
||||
next->prev = what;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add element to the linked list before a specified element
|
||||
*/
|
||||
void diva_q_insert_before (diva_entity_queue_t* q, diva_entity_link_t* next, diva_entity_link_t* what)
|
||||
{
|
||||
diva_entity_link_t *prev;
|
||||
|
||||
if(!next){
|
||||
diva_q_add_tail(q,what);
|
||||
return;
|
||||
}
|
||||
if(0 == (prev=diva_q_get_prev(next))){/*next seems to be the head*/
|
||||
q->head=what;
|
||||
what->prev=0;
|
||||
what->next=next;
|
||||
next->prev=what;
|
||||
}else{ /*not the head*/
|
||||
what->prev = prev;
|
||||
what->next = next;
|
||||
prev->next = what;
|
||||
next->prev = what;
|
||||
}
|
||||
}
|
||||
|
||||
diva_entity_link_t* diva_q_find (const diva_entity_queue_t* q, const void* what,
|
||||
diva_q_cmp_fn_t cmp_fn)
|
||||
{
|
||||
diva_entity_link_t* diva_q_current = q->head;
|
||||
|
||||
while (diva_q_current) {
|
||||
if (!(*cmp_fn)(what, diva_q_current)) {
|
||||
break;
|
||||
}
|
||||
diva_q_current = diva_q_current->next;
|
||||
}
|
||||
|
||||
return (diva_q_current);
|
||||
}
|
||||
|
||||
diva_entity_link_t*
|
||||
diva_q_get_head (const diva_entity_queue_t* q)
|
||||
{
|
||||
return (q->head);
|
||||
}
|
||||
|
||||
diva_entity_link_t*
|
||||
diva_q_get_tail (const diva_entity_queue_t* q)
|
||||
{
|
||||
return (q->tail);
|
||||
}
|
||||
|
||||
diva_entity_link_t*
|
||||
diva_q_get_next (const diva_entity_link_t* what)
|
||||
{
|
||||
return ((what) ? what->next : 0);
|
||||
}
|
||||
|
||||
diva_entity_link_t*
|
||||
diva_q_get_prev (const diva_entity_link_t* what)
|
||||
{
|
||||
return ((what) ? what->prev : 0);
|
||||
}
|
||||
|
||||
int
|
||||
diva_q_get_nr_of_entries (const diva_entity_queue_t* q)
|
||||
{
|
||||
int i = 0;
|
||||
const diva_entity_link_t* diva_q_current = q->head;
|
||||
|
||||
while (diva_q_current) {
|
||||
i++;
|
||||
diva_q_current = diva_q_current->next;
|
||||
}
|
||||
|
||||
return (i);
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
*
|
||||
Copyright (c) Dialogic, 2009.
|
||||
*
|
||||
This source file is supplied for the use with
|
||||
Dialogic range of DIVA Server Adapters.
|
||||
*
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
*
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
*
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef __DIVA_LINK_H__
|
||||
#define __DIVA_LINK_H__
|
||||
|
||||
struct _diva_entity_link;
|
||||
typedef struct _diva_entity_link {
|
||||
struct _diva_entity_link* prev;
|
||||
struct _diva_entity_link* next;
|
||||
} diva_entity_link_t;
|
||||
|
||||
typedef struct _diva_entity_queue {
|
||||
diva_entity_link_t* head;
|
||||
diva_entity_link_t* tail;
|
||||
} diva_entity_queue_t;
|
||||
|
||||
typedef int (*diva_q_cmp_fn_t)(const void* what,
|
||||
const diva_entity_link_t*);
|
||||
|
||||
void diva_q_remove (diva_entity_queue_t* q, diva_entity_link_t* what);
|
||||
void diva_q_add_tail (diva_entity_queue_t* q, diva_entity_link_t* what);
|
||||
void diva_q_insert_after (diva_entity_queue_t* q, diva_entity_link_t* prev, diva_entity_link_t* what);
|
||||
void diva_q_insert_before (diva_entity_queue_t* q, diva_entity_link_t* next, diva_entity_link_t* what);
|
||||
diva_entity_link_t* diva_q_find (const diva_entity_queue_t* q,
|
||||
const void* what, diva_q_cmp_fn_t cmp_fn);
|
||||
|
||||
diva_entity_link_t* diva_q_get_head (const diva_entity_queue_t* q);
|
||||
diva_entity_link_t* diva_q_get_tail (const diva_entity_queue_t* q);
|
||||
diva_entity_link_t* diva_q_get_next (const diva_entity_link_t* what);
|
||||
diva_entity_link_t* diva_q_get_prev (const diva_entity_link_t* what);
|
||||
int diva_q_get_nr_of_entries (const diva_entity_queue_t* q);
|
||||
void diva_q_init (diva_entity_queue_t* q);
|
||||
|
||||
#endif
|
Loading…
Reference in new issue