2
* @file ecasoundc_sa.cpp Standalone C implementation of the
3
* ecasound control interface
6
/* FIXME: add check for big sync-error -> ecasound probably
7
* died so better to give an error */
8
/* FIXME: add check for msgsize errors */
10
/** ------------------------------------------------------------------------
11
* ecasoundc.cpp: Standalone C implementation of the
12
* ecasound control interface
13
* Copyright (C) 2000-2006,2008,2009 Kai Vehmanen
14
* Copyright (C) 2003 Michael Ewe
15
* Copyright (C) 2001 Aymeric Jeanneau
17
* This library is free software; you can redistribute it and/or
18
* modify it under the terms of the GNU Lesser General Public
19
* License as published by the Free Software Foundation; either
20
* version 2.1 of the License, or (at your option) any later version.
22
* This library is distributed in the hope that it will be useful,
23
* but WITHOUT ANY WARRANTY; without even the implied warranty of
24
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25
* Lesser General Public License for more details.
27
* You should have received a copy of the GNU Lesser General Public
28
* License along with this library; if not, write to the Free Software
29
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31
* -------------------------------------------------------------------------
32
* History of major changes:
34
* 2009-02-08 Kai Vehmanen
35
* - Finally got rid of the fixed-size parsing buffers.
36
* - Added handling (or proper ignoring) of SIGPIPE signals.
37
* 2006-12-06 Kai Vehmanen
38
* - Fixed severe string termination bug in handling lists of
40
* - Fixed mechanism for waiting on grandchild ecasound process to exit.
41
* 2003-12-24 Michael Ewe
42
* - Fixed signaling issues on FreeBSD. Modified to perform a
43
* double-fork to better decouple ECI stack and the ecasound
45
* 2002-10-04 Kai Vehmanen
46
* - Rewritten as a standalone implementation.
47
* 2001-06-04 Aymeric Jeanneau
48
* - Added reentrant versions of all public ECI functions.
49
* 2000-12-06 Kai Vehmanen
52
* -------------------------------------------------------------------------
56
#include <stdio.h> /* ANSI-C: printf(), ... */
57
#include <stdlib.h> /* ANSI-C: calloc(), free() */
58
#include <string.h> /* ANSI-C: strlen() */
59
#include <errno.h> /* ANSI-C: errno */
62
#include <fcntl.h> /* POSIX: fcntl() */
63
#include <sys/poll.h> /* XPG4-UNIX: poll() */
64
#include <unistd.h> /* POSIX: pipe(), fork() */
65
#include <sys/stat.h> /* POSIX: stat() */
66
#include <sys/types.h> /* POSIX: fork() */
67
#include <sys/wait.h> /* POSIX: wait() */
68
#include <signal.h> /* POSIX: signal handling */
70
#include "ecasoundc.h"
72
/* ---------------------------------------------------------------------
76
// #define ECI_ENABLE_DEBUG
78
/* ---------------------------------------------------------------------
79
* Definitions and constants
82
#define ECI_PARSER_BUF_SIZE 65536
84
#define ECI_MAX_DYN_ALLOC_SIZE 16777216 /* assert if reached */
85
#define ECI_MAX_FLOAT_BUF_SIZE 32
86
#define ECI_MAX_RETURN_TYPE_SIZE 4
87
#define ECI_INI_STRING_SIZE 64
88
#define ECI_MAX_RESYNC_ATTEMPTS 9
89
#define ECI_MAX_LAST_COMMAND_SIZE 64
91
#define ECI_READ_TIMEOUT_MS 5000
92
#define ECI_READ_RETVAL_TIMEOUT_MS 30000
94
#define ECI_STATE_INIT 0
95
#define ECI_STATE_LOGLEVEL 1
96
#define ECI_STATE_MSGSIZE 2
97
#define ECI_STATE_COMMON_CR_1 3
98
#define ECI_STATE_COMMON_LF_1 4
99
#define ECI_STATE_RET_TYPE 5
100
#define ECI_STATE_COMMON_CONTENT 6
101
#define ECI_STATE_COMMON_CR_2 7
102
#define ECI_STATE_COMMON_LF_2 8
103
#define ECI_STATE_COMMON_CR_3 9
104
#define ECI_STATE_COMMON_LF_3 10
105
#define ECI_STATE_SEEK_TO_LF 11
107
#define ECI_STATE_MSG_GEN 0
108
#define ECI_STATE_MSG_RETURN 1
110
#define ECI_TOKEN_PHASE_NONE 0
111
#define ECI_TOKEN_PHASE_READING 1
112
#define ECI_TOKEN_PHASE_VALIDATE 2
114
#define ECI_RETURN_TYPE_LOGLEVEL 256
116
#ifdef ECI_ENABLE_DEBUG
117
#define ECI_DEBUG(x) fprintf(stderr,x)
118
#define ECI_DEBUG_1(x,y) fprintf(stderr,x,y)
119
#define ECI_DEBUG_2(x,y,z) fprintf(stderr,x,y,z)
120
#define ECI_DEBUG_3(x,y,z,t) fprintf(stderr,x,y,z,t)
122
#define ECI_DEBUG(x) ((void) 0)
123
#define ECI_DEBUG_1(x,y) ((void) 0)
124
#define ECI_DEBUG_2(x,y,z) ((void) 0)
125
#define ECI_DEBUG_3(x,y,z,t) ((void) 0)
128
#define DBC_REQUIRE(expr) \
129
(expr) ? (void)(0) : (void)(fprintf(stderr, "Warning: DBC_REQUIRE failed - \"%s\", %s, %d.\n", #expr,__FILE__, __LINE__))
130
#define DBC_ENSURE(expr) \
131
(expr) ? (void)(0) : (void)(fprintf(stderr, "Warning: DBC_ENSURE failed - \"%s\", %s, %d.\n", #expr,__FILE__, __LINE__))
132
#define DBC_CHECK(expr) \
133
(expr) ? (void)(0) : (void)(fprintf(stderr, "Warning: DBC_CHECK failed - \"%s\", %s, %d.\n", #expr,__FILE__, __LINE__))
134
#define DBC_DECLARE(expr) expr
136
/* ---------------------------------------------------------------------
140
struct eci_string_s {
141
char *d; /* buffer to string contents */
142
int slen; /* string length in octets, including terminating null */
143
int size; /* buffer length in octets, including terminating null */
145
typedef struct eci_string_s eci_string;
147
struct eci_los_list {
148
struct eci_los_list* prev_repp;
149
struct eci_los_list* next_repp;
150
eci_string data_repp;
159
long int last_li_rep;
161
int last_counter_rep;
162
char last_type_repp[ECI_MAX_RETURN_TYPE_SIZE];
163
struct eci_los_list* last_los_repp;
164
eci_string last_error_repp;
165
eci_string last_s_repp;
167
eci_string buffer_rep;
173
int buffer_current_rep;
178
struct eci_internal {
179
int pid_of_child_rep;
180
int pid_of_parent_rep;
182
int cmd_write_fd_rep;
184
char last_command_repp[ECI_MAX_LAST_COMMAND_SIZE];
185
int commands_counter_rep;
187
struct eci_parser* parser_repp;
189
char farg_buf_repp[ECI_MAX_FLOAT_BUF_SIZE];
190
char raw_buffer_repp[ECI_PARSER_BUF_SIZE];
193
/* ---------------------------------------------------------------------
197
static eci_handle_t static_eci_rep = 0;
200
* Message shown if ECASOUND is not defined.
202
const char* eci_str_no_ecasound_env =
204
"***********************************************************************\n"
205
"* Message from libecasoundc:\n"
207
"* 'ECASOUND' environment variable not set. Using the default value \n"
208
"* value 'ECASOUND=ecasound'.\n"
209
"***********************************************************************\n"
212
const char* eci_str_null_handle =
214
"***********************************************************************\n"
215
"* Message from libecasoundc:\n"
217
"* A null client handle detected. This is usually caused by a bug \n"
218
"* in the ECI application. Please report this bug to the author of\n"
220
"***********************************************************************\n"
223
const char* eci_str_sync_lost =
225
"***********************************************************************\n"
226
"* Message from libecasoundc:\n"
228
"* Connection to the processing engine was lost. Check that ecasound \n"
229
"* is correctly installed. Also make sure that ecasound is either \n"
230
"* in some directory listed in PATH, or the environment variable\n"
231
"* 'ECASOUND' contains the path to a working ecasound executable.\n"
232
"***********************************************************************\n"
235
/* ---------------------------------------------------------------------
236
* Declarations of static functions
239
static void eci_impl_check_handle(struct eci_internal* eci_rep);
240
static void eci_impl_free_parser(struct eci_internal* eci_rep);
241
static void eci_impl_clean_last_values(struct eci_parser* parser);
242
static void eci_impl_dump_parser_state(eci_handle_t ptr, const char* message);
243
static ssize_t eci_impl_fd_read(int fd, void *buf, size_t count, int timeout);
244
static const char* eci_impl_get_ecasound_path(void);
245
static struct eci_los_list *eci_impl_los_list_add_item(struct eci_los_list* headptr, char* stmp, int len);
246
static struct eci_los_list *eci_impl_los_list_alloc_item(void);
247
static void eci_impl_los_list_clear(struct eci_los_list *ptr);
248
static void eci_impl_read_return_value(struct eci_internal* eci_rep, int timeout);
249
static void eci_impl_set_last_los_value(struct eci_parser* parser);
250
static void eci_impl_set_last_values(struct eci_parser* parser);
251
static void eci_impl_update_state(struct eci_parser* eci_rep, char c);
253
/* ---------------------------------------------------------------------
254
* Constructing and destructing
258
* Initializes session. This call clears all status info and
259
* prepares ecasound for processing. Can be used to "restart"
264
DBC_CHECK(static_eci_rep == NULL);
265
static_eci_rep = eci_init_r();
269
* Initializes session. This call creates a new ecasound
270
* instance and prepares it for processing.
272
* @return NULL if initialization fails
274
eci_handle_t eci_init_r(void)
276
struct eci_internal* eci_rep = NULL;
277
int cmd_send_pipe[2], cmd_receive_pipe[2];
278
const char* ecasound_exec = eci_impl_get_ecasound_path();
280
/* step: launch ecasound process and setup two-way communication */
281
if (ecasound_exec != NULL &&
282
(pipe(cmd_receive_pipe) == 0 && pipe(cmd_send_pipe) == 0)) {
283
int fork_pid = fork();
286
/* first child (phase-1) */
288
/* -c = interactive mode, -D = direct prompts and banners to stderr */
289
const char* args[4] = { NULL, "-c", "-D", NULL };
294
sa.sa_handler=SIG_IGN;
295
sigemptyset(&sa.sa_mask);
297
sigaction(SIGHUP, &sa, NULL);
300
/* step: 2nd fork (to detach from parent) */
302
_exit(0); /* first child terminates here (phase-2) */
304
/* second child continues (phase-2) */
306
args[0] = ecasound_exec;
308
/* close all unused descriptors and resources */
313
dup2(cmd_send_pipe[0], 0);
314
dup2(cmd_receive_pipe[1], 1);
316
close(cmd_receive_pipe[0]);
317
close(cmd_receive_pipe[1]);
318
close(cmd_send_pipe[0]);
319
close(cmd_send_pipe[1]);
321
freopen("/dev/null", "w", stderr);
323
/* step: write second child's pid to the (grand) parent */
325
write(1, &pid, sizeof(pid));
327
/* step: notify the parent that we're up */
328
res = write(1, args, 1);
330
res = execvp(args[0], (char**)args);
331
if (res < 0) printf("(ecasoundc_sa) launching ecasound FAILED!\n");
337
ECI_DEBUG("(ecasoundc_sa) You shouldn't see this!\n");
340
/* step: parent (phase-1) */
346
/* set up signal handling */
347
struct sigaction ign_handler;
348
ign_handler.sa_handler = SIG_IGN;
349
sigemptyset(&ign_handler.sa_mask);
350
ign_handler.sa_flags = 0;
351
/* ignore the following signals */
352
sigaction(SIGPIPE, &ign_handler, 0);
353
sigaction(SIGFPE, &ign_handler, 0);
355
eci_rep = (struct eci_internal*)calloc(1, sizeof(struct eci_internal));
356
eci_rep->parser_repp = (struct eci_parser*)calloc(1, sizeof(struct eci_parser));
358
/* step: initialize variables */
359
eci_rep->pid_of_child_rep = fork_pid;
360
eci_rep->commands_counter_rep = 0;
361
eci_rep->parser_repp->last_counter_rep = 0;
362
eci_rep->parser_repp->token_phase_rep = ECI_TOKEN_PHASE_NONE;
363
eci_rep->parser_repp->buffer_current_rep = 0;
364
eci_rep->parser_repp->sync_lost_rep = false;
365
eci_impl_clean_last_values(eci_rep->parser_repp);
368
waits for first child to prevent the zombie
369
read grand child prozess id from pipe
371
waitpid(eci_rep->pid_of_child_rep, &status, 0);
372
res = read(cmd_receive_pipe[0], &pid, sizeof(pid));
373
if ( res != sizeof(pid) ) {
374
ECI_DEBUG_1("(ecasoundc_sa) fork() of %s FAILED!\n", ecasound_exec);
375
eci_impl_free_parser(eci_rep);
379
eci_rep->pid_of_child_rep = pid;
380
eci_rep->pid_of_parent_rep = getpid();
382
eci_rep->cmd_read_fd_rep = cmd_receive_pipe[0];
383
close(cmd_receive_pipe[1]);
384
eci_rep->cmd_write_fd_rep = cmd_send_pipe[1];
385
close(cmd_send_pipe[0]);
387
/* step: switch to non-blocking mode for read */
388
fcntl(eci_rep->cmd_read_fd_rep, F_SETFL, O_NONBLOCK);
389
fcntl(eci_rep->cmd_write_fd_rep, F_SETFL, O_NONBLOCK);
391
/* step: check that fork succeeded() */
392
res = eci_impl_fd_read(eci_rep->cmd_read_fd_rep, buf, 1, ECI_READ_TIMEOUT_MS);
394
ECI_DEBUG_1("(ecasoundc_sa) fork() of %s FAILED!\n", ecasound_exec);
395
eci_impl_free_parser(eci_rep);
400
write(eci_rep->cmd_write_fd_rep, "debug 256\n", strlen("debug 256\n"));
401
write(eci_rep->cmd_write_fd_rep, "int-set-float-to-string-precision 17\n", strlen("int-set-float-to-string-precision 17\n"));
402
write(eci_rep->cmd_write_fd_rep, "int-output-mode-wellformed\n", strlen("int-output-mode-wellformed\n"));
403
eci_rep->commands_counter_rep ++;
405
/* step: check that exec() succeeded */
406
eci_impl_read_return_value(eci_rep, ECI_READ_TIMEOUT_MS);
407
if (eci_rep->commands_counter_rep != eci_rep->parser_repp->last_counter_rep) {
408
ECI_DEBUG_3("(ecasoundc_sa) exec() of %s FAILED (%d=%d)!\n", ecasound_exec, eci_rep->commands_counter_rep, eci_rep->parser_repp->last_counter_rep);
409
eci_impl_free_parser(eci_rep);
417
return (eci_handle_t)eci_rep;
421
* Checks whether ECI is ready for use.
423
* @return non-zero if ready, zero otherwise
427
return eci_ready_r(static_eci_rep);
431
* Checks whether ECI is ready for use.
433
* @return non-zero if ready, zero otherwise
435
int eci_ready_r(eci_handle_t ptr)
437
struct eci_internal* eci_rep = (struct eci_internal*)ptr;
442
if (eci_rep->pid_of_child_rep <= 0 ||
443
eci_rep->cmd_read_fd_rep < 0 ||
444
eci_rep->cmd_write_fd_rep < 0)
451
* Frees all resources.
453
void eci_cleanup(void)
455
if (static_eci_rep != NULL) {
456
eci_cleanup_r(static_eci_rep);
457
static_eci_rep = NULL;
462
* Frees all resources.
464
void eci_cleanup_r(eci_handle_t ptr)
466
struct eci_internal* eci_rep = (struct eci_internal*)ptr;
467
ssize_t resread = 1, respoll;
469
struct pollfd fds[1];
471
eci_impl_check_handle(eci_rep);
473
ECI_DEBUG("\n(ecasoundc_sa) requesting to terminatte ecasound process.\n");
475
write(eci_rep->cmd_write_fd_rep, "quit\n", strlen("quit\n"));
476
eci_rep->commands_counter_rep++;
478
/* as we use double-fork, we cannot use waitpid() --
479
* to block until ecasound grandchild has exited, we
480
* use a combination of poll+read(),
481
* ref: http://www.greenend.org.uk/rjk/2001/06/poll.html
484
ECI_DEBUG_1("\n(ecasoundc_sa) cleaning up. waiting for grandchild ecasound process %d.\n", eci_rep->pid_of_child_rep);
486
while (resread > 0) {
487
fds[0].fd = eci_rep->cmd_read_fd_rep;
488
fds[0].events = POLLIN;
490
respoll = poll(fds, 1, ECI_READ_RETVAL_TIMEOUT_MS);
491
if (fds[0].revents & (POLLIN | POLLHUP))
492
resread = read(eci_rep->cmd_read_fd_rep, buf, 1);
493
else if (fds[0].revents & POLLERR)
496
ECI_DEBUG_3("(ecasoundc_sa) waiting for ecasound, poll=%d, read=%d, revents=0x%02x)\n", respoll, resread, fds[0].revents);
499
ECI_DEBUG("(ecasoundc_sa) child exited\n");
502
/* close descriptors */
503
close(eci_rep->cmd_read_fd_rep);
504
close(eci_rep->cmd_write_fd_rep);
506
/* free lists of strings, if any */
507
eci_impl_clean_last_values(eci_rep->parser_repp);
509
eci_impl_free_parser(eci_rep);
514
/* ---------------------------------------------------------------------
515
* Issuing EIAM commands
519
* Sends a command to the ecasound engine. See ecasound-iam(5) for
522
void eci_command(const char* command) { eci_command_r(static_eci_rep, command); }
525
* Sends a command to the ecasound engine. See ecasound-iam(5) for
528
void eci_command_r(eci_handle_t ptr, const char* command)
530
struct eci_internal* eci_rep = (struct eci_internal*)ptr;
531
int timeout = ECI_READ_RETVAL_TIMEOUT_MS;
533
eci_impl_check_handle(eci_rep);
535
if (eci_ready_r(ptr) == 0) {
536
ECI_DEBUG("(ecasoundc_sa) not ready, unable to process commands\n");
540
ECI_DEBUG_2("(ecasoundc_sa) writing command '%s' (cmd-counter=%d).\n",
541
command, eci_rep->commands_counter_rep + 1);
543
memcpy(eci_rep->last_command_repp, command, ECI_MAX_LAST_COMMAND_SIZE);
545
eci_impl_clean_last_values(eci_rep->parser_repp);
547
write(eci_rep->cmd_write_fd_rep, command, strlen(command));
548
write(eci_rep->cmd_write_fd_rep, "\n", 1);
550
/* 'run' is the only blocking function */
551
if (strncmp(command, "run", 3) == 0) {
552
ECI_DEBUG("(ecasoundc_sa) 'run' detected; disabling reply timeout!\n");
556
eci_rep->commands_counter_rep++;
558
if (eci_rep->commands_counter_rep - 1 !=
559
eci_rep->parser_repp->last_counter_rep) {
560
eci_impl_dump_parser_state(ptr, "sync error");
561
eci_rep->parser_repp->sync_lost_rep = true;
564
if (eci_rep->commands_counter_rep >=
565
eci_rep->parser_repp->last_counter_rep) {
566
eci_impl_read_return_value(eci_rep, timeout);
569
ECI_DEBUG_2("(ecasoundc_sa) set return value type='%s' (read-counter=%d).\n",
570
eci_rep->parser_repp->last_type_repp, eci_rep->parser_repp->last_counter_rep);
572
if (eci_rep->commands_counter_rep >
573
eci_rep->parser_repp->last_counter_rep) {
574
fprintf(stderr, "%s", eci_str_sync_lost);
575
eci_rep->parser_repp->sync_lost_rep = true;
580
* A specialized version of 'eci_command()' taking a double value
581
* as the 2nd argument.
583
void eci_command_float_arg(const char* command, double arg) { eci_command_float_arg_r(static_eci_rep, command, arg); }
586
* A specialized version of 'eci_command()' taking a double value
587
* as the 2nd argument.
589
void eci_command_float_arg_r(eci_handle_t ptr, const char* command, double arg)
591
struct eci_internal* eci_rep = (struct eci_internal*)ptr;
593
eci_impl_check_handle(eci_rep);
595
snprintf(eci_rep->farg_buf_repp, ECI_MAX_FLOAT_BUF_SIZE-1, "%s %.32f", command, arg);
596
eci_command_r(ptr, eci_rep->farg_buf_repp);
599
/* ---------------------------------------------------------------------
600
* Getting return values
604
* Returns the number of strings returned by the
607
int eci_last_string_list_count(void) { return(eci_last_string_list_count_r(static_eci_rep)); }
610
* Returns the number of strings returned by the
613
int eci_last_string_list_count_r(eci_handle_t ptr)
615
struct eci_internal* eci_rep = (struct eci_internal*)ptr;
616
struct eci_los_list* i;
619
eci_impl_check_handle(eci_rep);
621
for(i = eci_rep->parser_repp->last_los_repp;
631
* Returns the nth item of the list containing
632
* strings returned by the last ECI command.
635
* n >= 0 && n < eci_last_string_list_count()
637
const char* eci_last_string_list_item(int n) { return(eci_last_string_list_item_r(static_eci_rep, n)); }
640
* Returns the nth item of the list containing
641
* strings returned by the last ECI command.
644
* n >= 0 && n < eci_last_string_list_count()
646
const char* eci_last_string_list_item_r(eci_handle_t ptr, int n)
648
struct eci_internal* eci_rep = (struct eci_internal*)ptr;
649
struct eci_los_list* i;
652
eci_impl_check_handle(eci_rep);
654
for(i = eci_rep->parser_repp->last_los_repp;
658
return i->data_repp.d;
665
const char* eci_last_string(void) { return(eci_last_string_r(static_eci_rep)); }
667
const char* eci_last_string_r(eci_handle_t ptr)
669
struct eci_internal* eci_rep = (struct eci_internal*)ptr;
671
eci_impl_check_handle(eci_rep);
673
return eci_rep->parser_repp->last_s_repp.d;
676
double eci_last_float(void) { return(eci_last_float_r(static_eci_rep)); }
678
double eci_last_float_r(eci_handle_t ptr)
680
struct eci_internal* eci_rep = (struct eci_internal*)ptr;
682
eci_impl_check_handle(eci_rep);
684
return eci_rep->parser_repp->last_f_rep;
687
int eci_last_integer(void) { return(eci_last_integer_r(static_eci_rep)); }
689
int eci_last_integer_r(eci_handle_t ptr)
691
struct eci_internal* eci_rep = (struct eci_internal*)ptr;
693
eci_impl_check_handle(eci_rep);
695
return eci_rep->parser_repp->last_i_rep;
698
long int eci_last_long_integer(void) { return(eci_last_long_integer_r(static_eci_rep)); }
700
long int eci_last_long_integer_r(eci_handle_t ptr)
702
struct eci_internal* eci_rep = (struct eci_internal*)ptr;
704
eci_impl_check_handle(eci_rep);
706
return eci_rep->parser_repp->last_li_rep;
710
* Returns pointer to a null-terminated string containing
711
* information about the last occured error.
713
const char* eci_last_error(void) { return(eci_last_error_r(static_eci_rep)); }
716
* Returns pointer to a null-terminated string containing
717
* information about the last occured error.
719
const char* eci_last_error_r(eci_handle_t ptr)
721
struct eci_internal* eci_rep = (struct eci_internal*)ptr;
723
eci_impl_check_handle(eci_rep);
725
return eci_rep->parser_repp->last_error_repp.d;
729
const char* eci_last_type(void) { return(eci_last_type_r(static_eci_rep)); }
731
const char* eci_last_type_r(eci_handle_t ptr)
733
struct eci_internal* eci_rep = (struct eci_internal*)ptr;
735
eci_impl_check_handle(eci_rep);
737
return eci_rep->parser_repp->last_type_repp;
741
* Whether an error has occured?
743
* @return zero if not in error state
745
int eci_error(void) { return(eci_error_r(static_eci_rep)); }
748
* Whether an error has occured?
750
* @return zero if not in error state
752
int eci_error_r(eci_handle_t ptr)
754
struct eci_internal* eci_rep = (struct eci_internal*)ptr;
757
eci_impl_check_handle(eci_rep);
759
if (eci_ready_r(ptr) == 0) {
760
ECI_DEBUG("(ecasoundc_sa) not ready, raising an error\n");
764
if (eci_rep->parser_repp->sync_lost_rep == true) {
765
ECI_DEBUG("(ecasoundc_sa) sync lost, raising an error\n");
769
res = (eci_rep->parser_repp->last_type_repp[0] == 'e') ? 1 : 0;
771
ECI_DEBUG_1("(ecasoundc_sa) checking for error, returning %d", res);
776
/* ---------------------------------------------------------------------
780
int eci_events_available(void) { return(eci_events_available_r(static_eci_rep)); }
781
int eci_events_available_r(eci_handle_t ptr) { return(0); }
782
void eci_next_event(void) { eci_next_event_r(static_eci_rep); }
783
void eci_next_event_r(eci_handle_t ptr) { }
784
const char* eci_current_event(void) { return(eci_current_event_r(static_eci_rep)); }
785
const char* eci_current_event_r(eci_handle_t ptr) { return(0); }
787
/* ---------------------------------------------------------------------
788
* Implementation of static functions
791
static void eci_string_add(eci_string *dst, int at, char const *src, int len);
794
* Clears the string contents.
796
* @post eci_string_len(str)==0
797
* @post strlen(str->d)==0
799
static void eci_string_clear(eci_string *str)
804
eci_string_add(str, 0, NULL, 0);
807
DBC_CHECK(str->d[0] == 0);
811
* Initializes the string object for use.
812
* This must only be called after initial
815
static void eci_string_init(eci_string *str)
823
static void eci_string_free(eci_string *str)
832
* Returns the string length.
834
static int eci_string_len(eci_string *str)
841
* Adds 'len' octets from buffer 'src' to the string
842
* at position 'at' (position 0 being the first character).
844
static void eci_string_add(eci_string *dst, int at, char const *src, int len)
846
int space_needed = at + len + 1;
850
if (space_needed > dst->size) {
852
dst->size ? dst->size * 2 : ECI_INI_STRING_SIZE;
854
while (space_needed > newsize) {
857
assert(newsize <= ECI_MAX_DYN_ALLOC_SIZE);
858
newbuf = realloc(dst->d, newsize);
864
DBC_CHECK(space_needed <= dst->size);
866
memcpy(&dst->d[at], src, len);
867
dst->d[at + len] = 0;
870
static void eci_impl_check_handle(struct eci_internal* eci_rep)
872
if (eci_rep == NULL) {
873
fprintf(stderr, "%s", eci_str_null_handle);
874
DBC_CHECK(eci_rep != NULL);
879
static void eci_impl_free_parser(struct eci_internal* eci_rep)
882
eci_string_free(&eci_rep->parser_repp->last_error_repp);
883
eci_string_free(&eci_rep->parser_repp->last_s_repp);
884
eci_string_free(&eci_rep->parser_repp->buffer_rep);
885
free(eci_rep->parser_repp);
886
eci_rep->parser_repp = 0;
889
static void eci_impl_clean_last_values(struct eci_parser* parser)
891
DBC_CHECK(parser != 0);
893
eci_impl_los_list_clear(parser->last_los_repp);
894
parser->last_los_repp = NULL;
895
parser->last_i_rep = 0;
896
parser->last_li_rep = 0;
897
parser->last_f_rep = 0.0f;
898
eci_string_clear(&parser->last_error_repp);
899
eci_string_clear(&parser->last_s_repp);
902
static void eci_impl_dump_parser_state(eci_handle_t ptr, const char* message)
904
struct eci_internal* eci_rep = (struct eci_internal*)ptr;
906
fprintf(stderr, "\n(ecasoundc_sa) Error='%s', cmd='%s' last_error='%s' cmd_cnt=%d last_cnt=%d.\n",
908
eci_rep->last_command_repp,
909
eci_last_error_r(ptr),
910
eci_rep->commands_counter_rep,
911
eci_rep->parser_repp->last_counter_rep);
916
* Attempts to read up to 'count' bytes from file descriptor 'fd'
917
* into the buffer starting at 'buf'. If no data is available
918
* for reading, up to 'timeout' milliseconds will be waited.
919
* A negative value means infinite timeout.
921
static ssize_t eci_impl_fd_read(int fd, void *buf, size_t count, int timeout)
925
ssize_t rescount = 0;
929
ufds.events = POLLIN | POLLPRI;
932
ret = poll(&ufds, nfds, timeout);
934
if (ufds.revents & POLLIN ||
935
ufds.revents & POLLPRI) {
936
rescount = read(fd, buf, count);
946
static const char* eci_impl_get_ecasound_path(void)
948
const char* result = getenv("ECASOUND");
950
if (result == NULL) {
951
fprintf(stderr, "%s", eci_str_no_ecasound_env);
959
static struct eci_los_list *eci_impl_los_list_add_item(struct eci_los_list* head, char* stmp, int len)
961
struct eci_los_list* i = head;
962
struct eci_los_list* last = NULL;
964
/* find end of list */
970
/* add to the end, copy data */
971
i = eci_impl_los_list_alloc_item();
972
eci_string_add(&i->data_repp, 0, stmp, len);
973
if (last != NULL) last->next_repp = i;
975
/* ECI_DEBUG_3("(ecasoundc_sa) adding item '%s' to los list; head=%p, i=%p\n", stmp, (void*)head, (void*)i); */
977
/* created a new list, return the new item */
981
/* return the old head */
985
struct eci_los_list *eci_impl_los_list_alloc_item(void)
987
struct eci_los_list *item;
988
/* ECI_DEBUG("(ecasoundc_sa) list alloc item\n"); */
989
item = (struct eci_los_list*)calloc(1, sizeof(struct eci_los_list));
990
DBC_CHECK(item != NULL);
991
item->next_repp = item->prev_repp = NULL;
992
eci_string_clear(&item->data_repp);
997
static void eci_impl_los_list_clear(struct eci_los_list *ptr)
999
struct eci_los_list *i = ptr;
1001
ECI_DEBUG_1("(ecasoundc_sa) clearing list, i=%p\n", (void*)i);
1004
/* ECI_DEBUG_1("(ecasoundc_sa) freeing list item %p\n", (void*)i); */
1005
struct eci_los_list* next = i->next_repp;
1006
eci_string_free(&i->data_repp);
1012
static void eci_impl_read_return_value(struct eci_internal* eci_rep, int timeout)
1014
char* raw_buffer = eci_rep->raw_buffer_repp;
1017
DBC_CHECK(eci_rep->commands_counter_rep >=
1018
eci_rep->parser_repp->last_counter_rep);
1020
while(attempts < ECI_MAX_RESYNC_ATTEMPTS) {
1021
int res = eci_impl_fd_read(eci_rep->cmd_read_fd_rep, raw_buffer, ECI_PARSER_BUF_SIZE-1, timeout);
1025
raw_buffer[res] = 0;
1026
/* ECI_DEBUG_2("\n(ecasoundc_sa) read %u bytes:\n--cut--\n%s\n--cut--\n", res, raw_buffer); */
1028
for(n = 0; n < res; n++) {
1029
/* int old = eci_rep->parser_repp->state_rep; */
1030
eci_impl_update_state(eci_rep->parser_repp, raw_buffer[n]);
1031
/* if (old != eci_rep->parser_repp->state_rep) ECI_DEBUG_3("state change %d-%d, c=[%02X].\n", old, eci_rep->parser_repp->state_rep, raw_buffer[n]); */
1034
if (eci_rep->commands_counter_rep ==
1035
eci_rep->parser_repp->last_counter_rep) break;
1037
/* read return values until the correct one is found */
1041
ECI_DEBUG_1("(ecasoundc_sa) timeout when reading return values (attempts=%d)!\n", attempts);
1042
eci_rep->parser_repp->sync_lost_rep = true;
1049
if (eci_rep->commands_counter_rep !=
1050
eci_rep->parser_repp->last_counter_rep) {
1051
eci_impl_dump_parser_state(eci_rep, "read() error");
1052
eci_rep->parser_repp->sync_lost_rep = true;
1057
* Sets the last 'list of strings' values.
1060
* @pre parser->state_rep == ECI_STATE_COMMON_LF_3
1062
static void eci_impl_set_last_los_value(struct eci_parser* parser)
1064
struct eci_los_list* i = parser->last_los_repp;
1065
int quoteflag = 0, m = 0, n;
1067
eci_string_init(&stmp);
1069
DBC_CHECK(parser != 0);
1070
DBC_CHECK(parser->state_rep == ECI_STATE_COMMON_LF_3);
1072
ECI_DEBUG_2("(ecasoundc_sa) parsing a list '%s' (count=%d)\n", parser->buffer_rep.d, parser->buffer_current_rep);
1074
eci_impl_los_list_clear(i);
1075
parser->last_los_repp = NULL;
1077
for(n = 0; n < parser->buffer_current_rep && n < parser->msgsize_rep; n++) {
1078
char c = parser->buffer_rep.d[n];
1081
quoteflag = !quoteflag;
1083
else if (c == '\\') {
1085
eci_string_add(&stmp, m++, &parser->buffer_rep.d[n], 1);
1087
else if (c != ',' || quoteflag == 1) {
1088
eci_string_add(&stmp, m++, &parser->buffer_rep.d[n], 1);
1091
if (m == 0) continue;
1092
i = eci_impl_los_list_add_item(i, stmp.d, m);
1097
i = eci_impl_los_list_add_item(i, stmp.d, m);
1100
parser->last_los_repp = i;
1102
eci_string_free(&stmp);
1106
* Sets the 'last value' fields in the given 'parser'
1110
* @pre parser->state_rep == ECI_STATE_COMMON_LF_3
1112
static void eci_impl_set_last_values(struct eci_parser* parser)
1114
DBC_CHECK(parser != 0);
1115
DBC_CHECK(parser->state_rep == ECI_STATE_COMMON_LF_3);
1117
switch(parser->last_type_repp[0])
1120
eci_string_add(&parser->last_s_repp, 0, parser->buffer_rep.d, parser->buffer_current_rep);
1124
eci_impl_set_last_los_value(parser);
1128
parser->last_i_rep = atoi(parser->buffer_rep.d);
1132
parser->last_li_rep = atol(parser->buffer_rep.d);
1136
parser->last_f_rep = atof(parser->buffer_rep.d);
1140
eci_string_add(&parser->last_error_repp, 0, parser->buffer_rep.d, parser->buffer_current_rep);
1148
static void eci_impl_update_state(struct eci_parser* parser, char c)
1150
switch(parser->state_rep)
1152
case ECI_STATE_INIT:
1153
if (c >= 0x30 && c <= 0x39) {
1154
parser->token_phase_rep = ECI_TOKEN_PHASE_READING;
1155
parser->buffer_current_rep = 0;
1156
eci_string_clear(&parser->buffer_rep);
1157
parser->state_rep = ECI_STATE_LOGLEVEL;
1160
parser->token_phase_rep = ECI_TOKEN_PHASE_NONE;
1164
case ECI_STATE_LOGLEVEL:
1166
parser->loglevel_rep = atoi(parser->buffer_rep.d);
1168
if (parser->loglevel_rep == ECI_RETURN_TYPE_LOGLEVEL) {
1169
/* ECI_DEBUG_3("\n(ecasoundc_sa) found rettype loglevel '%s' (i=%d,len=%d).\n", parser->buffer_repp, parser->loglevel_rep, parser->buffer_current_rep); */
1170
parser->state_msg_rep = ECI_STATE_MSG_RETURN;
1173
/* ECI_DEBUG_3("\n(ecasoundc_sa) found loglevel '%s' (i=%d,parser->buffer_current_rep=%d).\n", buf, parser->loglevel_rep, parser->buffer_current_rep); */
1174
parser->state_msg_rep = ECI_STATE_MSG_GEN;
1177
parser->state_rep = ECI_STATE_MSGSIZE;
1178
parser->token_phase_rep = ECI_TOKEN_PHASE_NONE;
1180
else if (c < 0x30 && c > 0x39) {
1181
parser->state_rep = ECI_STATE_SEEK_TO_LF;
1186
case ECI_STATE_MSGSIZE:
1187
if ((c == ' ' && parser->state_msg_rep == ECI_STATE_MSG_RETURN) ||
1188
(c == 0x0d && parser->state_msg_rep == ECI_STATE_MSG_GEN)) {
1190
parser->msgsize_rep = atoi(parser->buffer_rep.d);
1192
/* ECI_DEBUG_3("(ecasoundc_sa) found msgsize '%s' (i=%d,len=%d).\n", parser->buffer_repp, parser->msgsize_rep, parser->buffer_current_rep); */
1194
if (parser->state_msg_rep == ECI_STATE_MSG_GEN) {
1195
parser->state_rep = ECI_STATE_COMMON_LF_1;
1198
parser->state_rep = ECI_STATE_RET_TYPE;
1201
parser->token_phase_rep = ECI_TOKEN_PHASE_NONE;
1204
else if (c < 0x30 && c > 0x39) {
1205
parser->state_rep = ECI_STATE_SEEK_TO_LF;
1207
else if (parser->token_phase_rep == ECI_TOKEN_PHASE_NONE) {
1208
parser->token_phase_rep = ECI_TOKEN_PHASE_READING;
1209
parser->buffer_current_rep = 0;
1210
eci_string_clear(&parser->buffer_rep);
1214
case ECI_STATE_COMMON_CR_1:
1216
parser->state_rep = ECI_STATE_COMMON_LF_1;
1218
parser->state_rep = ECI_STATE_INIT;
1221
case ECI_STATE_COMMON_LF_1:
1223
parser->state_rep = ECI_STATE_COMMON_CONTENT;
1226
parser->state_rep = ECI_STATE_INIT;
1229
case ECI_STATE_RET_TYPE:
1231
/* parse return type */
1232
/* set 'parser->last_type_repp' */
1233
int len = (parser->buffer_current_rep < ECI_MAX_RETURN_TYPE_SIZE) ? parser->buffer_current_rep : (ECI_MAX_RETURN_TYPE_SIZE - 1);
1235
memcpy(parser->last_type_repp, parser->buffer_rep.d, len);
1236
parser->last_type_repp[len] = 0;
1238
ECI_DEBUG_2("(ecasoundc_sa) found rettype '%s' (len=%d)\n", parser->last_type_repp, parser->buffer_current_rep);
1240
parser->state_rep = ECI_STATE_COMMON_LF_1;
1241
parser->token_phase_rep = ECI_TOKEN_PHASE_NONE;
1244
else if (parser->token_phase_rep == ECI_TOKEN_PHASE_NONE) {
1245
parser->token_phase_rep = ECI_TOKEN_PHASE_READING;
1246
parser->buffer_current_rep = 0;
1247
eci_string_clear(&parser->buffer_rep);
1252
case ECI_STATE_COMMON_CONTENT:
1254
/* parse return type */
1255
/* set 'parser->last_xxx_yyy' */
1257
/* handle empty content */
1258
if (parser->msgsize_rep == 0)
1259
eci_string_clear(&parser->buffer_rep);
1261
ECI_DEBUG_2("(ecasoundc_sa) found content, loglevel=%d, msgsize=%d", parser->loglevel_rep, parser->msgsize_rep);
1262
if (parser->state_msg_rep == ECI_STATE_MSG_GEN)
1265
ECI_DEBUG_1(" type='%s'.\n", parser->last_type_repp);
1267
parser->state_rep = ECI_STATE_COMMON_LF_2;
1268
parser->token_phase_rep = ECI_TOKEN_PHASE_VALIDATE;
1271
else if (parser->token_phase_rep == ECI_TOKEN_PHASE_NONE) {
1272
parser->token_phase_rep = ECI_TOKEN_PHASE_READING;
1273
parser->buffer_current_rep = 0;
1274
eci_string_clear(&parser->buffer_rep);
1278
case ECI_STATE_COMMON_CR_2:
1280
parser->state_rep = ECI_STATE_COMMON_LF_2;
1282
parser->state_rep = ECI_STATE_COMMON_CONTENT;
1285
case ECI_STATE_COMMON_LF_2:
1287
parser->state_rep = ECI_STATE_COMMON_CR_3;
1289
parser->state_rep = ECI_STATE_COMMON_CONTENT;
1292
case ECI_STATE_COMMON_CR_3:
1294
parser->state_rep = ECI_STATE_COMMON_LF_3;
1296
parser->state_rep = ECI_STATE_COMMON_CONTENT;
1299
case ECI_STATE_COMMON_LF_3:
1301
if (parser->state_msg_rep == ECI_STATE_MSG_RETURN) {
1302
ECI_DEBUG_1("(ecasoundc_sa) rettype-content validated: <<<%s>>>\n", parser->buffer_rep.d);
1303
eci_impl_set_last_values(parser);
1304
parser->last_counter_rep++;
1307
ECI_DEBUG_1("(ecasoundc_sa) gen-content validated: <<<%s>>>\n", parser->buffer_rep.d);
1309
parser->state_rep = ECI_STATE_INIT;
1312
parser->state_rep = ECI_STATE_COMMON_CONTENT;
1315
case ECI_STATE_SEEK_TO_LF:
1317
parser->token_phase_rep = ECI_TOKEN_PHASE_NONE;
1318
parser->state_rep = ECI_STATE_INIT;
1324
} /* end of switch() */
1326
if (parser->token_phase_rep == ECI_TOKEN_PHASE_READING) {
1327
eci_string_add(&parser->buffer_rep, parser->buffer_current_rep, &c, 1);
1328
++parser->buffer_current_rep;
1331
//ECI_DEBUG_2("(ecasoundc_sa) parser buf contents: '%s' (cur=%d)\n.", parser->buffer_rep.d, parser->buffer_current_rep);