~ubuntu-branches/ubuntu/wily/ecasound/wily-proposed

« back to all changes in this revision

Viewing changes to libecasoundc/ecasoundc_sa.c

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghedini
  • Date: 2011-05-12 17:58:03 UTC
  • Revision ID: james.westby@ubuntu.com-20110512175803-zy3lodjecabt9r3v
Tags: upstream-2.8.0
ImportĀ upstreamĀ versionĀ 2.8.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** 
 
2
 * @file ecasoundc_sa.cpp Standalone C implementation of the 
 
3
 *                        ecasound control interface
 
4
 */
 
5
 
 
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 */
 
9
 
 
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
 
16
 *
 
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.
 
21
 *
 
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.
 
26
 *
 
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
 
30
 *
 
31
 * -------------------------------------------------------------------------
 
32
 * History of major changes:
 
33
 *
 
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
 
39
 *       strings.
 
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
 
44
 *       engine process.
 
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
 
50
 *     - Initial version.
 
51
 *
 
52
 * -------------------------------------------------------------------------
 
53
 */
 
54
 
 
55
#include <assert.h>
 
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 */
 
60
#include <stdbool.h>
 
61
 
 
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 */
 
69
 
 
70
#include "ecasoundc.h"
 
71
 
 
72
/* --------------------------------------------------------------------- 
 
73
 * Options
 
74
 */
 
75
 
 
76
// #define ECI_ENABLE_DEBUG
 
77
 
 
78
/* --------------------------------------------------------------------- 
 
79
 * Definitions and constants
 
80
 */
 
81
 
 
82
#define ECI_PARSER_BUF_SIZE        65536
 
83
 
 
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
 
90
 
 
91
#define ECI_READ_TIMEOUT_MS        5000
 
92
#define ECI_READ_RETVAL_TIMEOUT_MS 30000
 
93
 
 
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
 
106
 
 
107
#define ECI_STATE_MSG_GEN          0
 
108
#define ECI_STATE_MSG_RETURN       1
 
109
 
 
110
#define ECI_TOKEN_PHASE_NONE       0
 
111
#define ECI_TOKEN_PHASE_READING    1
 
112
#define ECI_TOKEN_PHASE_VALIDATE   2
 
113
 
 
114
#define ECI_RETURN_TYPE_LOGLEVEL   256
 
115
 
 
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)
 
121
#else
 
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)
 
126
#endif
 
127
 
 
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
 
135
 
 
136
/* --------------------------------------------------------------------- 
 
137
 * Data structures 
 
138
 */
 
139
 
 
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 */
 
144
};
 
145
typedef struct eci_string_s eci_string;
 
146
 
 
147
struct eci_los_list {
 
148
  struct eci_los_list* prev_repp;
 
149
  struct eci_los_list* next_repp;
 
150
  eci_string data_repp;
 
151
};
 
152
 
 
153
struct eci_parser { 
 
154
 
 
155
  int state_rep;
 
156
  int state_msg_rep;
 
157
 
 
158
  double last_f_rep;
 
159
  long int last_li_rep;
 
160
  int last_i_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;
 
166
 
 
167
  eci_string buffer_rep;
 
168
 
 
169
  int msgsize_rep;
 
170
  int loglevel_rep;
 
171
 
 
172
  int token_phase_rep;
 
173
  int buffer_current_rep;
 
174
 
 
175
  bool sync_lost_rep;
 
176
};
 
177
 
 
178
struct eci_internal { 
 
179
  int pid_of_child_rep;
 
180
  int pid_of_parent_rep;
 
181
  int cmd_read_fd_rep;
 
182
  int cmd_write_fd_rep;
 
183
 
 
184
  char last_command_repp[ECI_MAX_LAST_COMMAND_SIZE];
 
185
  int commands_counter_rep;
 
186
 
 
187
  struct eci_parser* parser_repp;
 
188
 
 
189
  char farg_buf_repp[ECI_MAX_FLOAT_BUF_SIZE];
 
190
  char raw_buffer_repp[ECI_PARSER_BUF_SIZE];
 
191
};
 
192
 
 
193
/* --------------------------------------------------------------------- 
 
194
 * Global variables
 
195
 */
 
196
 
 
197
static eci_handle_t static_eci_rep = 0;
 
198
 
 
199
/**
 
200
 * Message shown if ECASOUND is not defined.
 
201
 */
 
202
const char* eci_str_no_ecasound_env = 
 
203
    "\n"
 
204
    "***********************************************************************\n"
 
205
    "* Message from libecasoundc:\n"
 
206
    "* \n"
 
207
    "* 'ECASOUND' environment variable not set. Using the default value \n"
 
208
    "* value 'ECASOUND=ecasound'.\n"
 
209
    "***********************************************************************\n"
 
210
    "\n";
 
211
 
 
212
const char* eci_str_null_handle = 
 
213
    "\n"
 
214
    "***********************************************************************\n"
 
215
    "* Message from libecasoundc:\n"
 
216
    "* \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"
 
219
    "* the program.\n"
 
220
    "***********************************************************************\n"
 
221
    "\n";
 
222
 
 
223
const char* eci_str_sync_lost =
 
224
    "\n"
 
225
    "***********************************************************************\n"
 
226
    "* Message from libecasoundc:\n"
 
227
    "* \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"
 
233
    "\n";
 
234
 
 
235
/* --------------------------------------------------------------------- 
 
236
 * Declarations of static functions
 
237
 */
 
238
 
 
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);
 
252
 
 
253
/* ---------------------------------------------------------------------
 
254
 * Constructing and destructing                                       
 
255
 */
 
256
 
 
257
/**
 
258
 * Initializes session. This call clears all status info and
 
259
 * prepares ecasound for processing. Can be used to "restart"
 
260
 * the library.
 
261
 */
 
262
void eci_init(void)
 
263
{
 
264
  DBC_CHECK(static_eci_rep == NULL);
 
265
  static_eci_rep = eci_init_r();
 
266
}
 
267
 
 
268
/**
 
269
 * Initializes session. This call creates a new ecasound
 
270
 * instance and prepares it for processing. 
 
271
 *
 
272
 * @return NULL if initialization fails
 
273
 */
 
274
eci_handle_t eci_init_r(void)
 
275
{
 
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();
 
279
 
 
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();
 
284
    /* step: 1st fork */
 
285
    if (fork_pid == 0) { 
 
286
      /* first child (phase-1) */
 
287
 
 
288
      /* -c = interactive mode, -D = direct prompts and banners to stderr */
 
289
      const char* args[4] = { NULL, "-c", "-D", NULL };
 
290
      int res = 0;
 
291
      struct sigaction sa;
 
292
      pid_t pid;
 
293
 
 
294
      sa.sa_handler=SIG_IGN;
 
295
      sigemptyset(&sa.sa_mask);
 
296
      sa.sa_flags=0;
 
297
      sigaction(SIGHUP, &sa, NULL);
 
298
      setsid();
 
299
 
 
300
      /* step: 2nd fork (to detach from parent) */
 
301
      if (fork() != 0)
 
302
          _exit(0);    /* first child terminates here (phase-2) */
 
303
 
 
304
      /* second child continues (phase-2) */
 
305
     
 
306
      args[0] = ecasound_exec;
 
307
 
 
308
      /* close all unused descriptors and resources */
 
309
 
 
310
      close(0);
 
311
      close(1);
 
312
 
 
313
      dup2(cmd_send_pipe[0], 0);
 
314
      dup2(cmd_receive_pipe[1], 1);
 
315
 
 
316
      close(cmd_receive_pipe[0]);
 
317
      close(cmd_receive_pipe[1]);
 
318
      close(cmd_send_pipe[0]);
 
319
      close(cmd_send_pipe[1]);
 
320
 
 
321
      freopen("/dev/null", "w", stderr);
 
322
 
 
323
      /* step: write second child's pid to the (grand) parent */
 
324
      pid = getpid();
 
325
      write(1, &pid, sizeof(pid));
 
326
      
 
327
      /* step: notify the parent that we're up */
 
328
      res = write(1, args, 1); 
 
329
 
 
330
      res = execvp(args[0], (char**)args);
 
331
      if (res < 0) printf("(ecasoundc_sa) launching ecasound FAILED!\n");
 
332
 
 
333
      close(0);
 
334
      close(1);
 
335
 
 
336
      _exit(res);
 
337
      ECI_DEBUG("(ecasoundc_sa) You shouldn't see this!\n");
 
338
    }
 
339
    else { 
 
340
      /* step: parent (phase-1) */
 
341
      int res;
 
342
      char buf[1];
 
343
      int status;
 
344
      int pid;
 
345
 
 
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);
 
354
 
 
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));
 
357
 
 
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);
 
366
 
 
367
      /*
 
368
        waits for first child to prevent the zombie
 
369
        read grand child prozess id from pipe
 
370
      */
 
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);
 
376
          free(eci_rep);
 
377
          eci_rep = NULL;
 
378
      }
 
379
      eci_rep->pid_of_child_rep = pid;
 
380
      eci_rep->pid_of_parent_rep = getpid();
 
381
 
 
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]);
 
386
 
 
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);
 
390
 
 
391
      /* step: check that fork succeeded() */
 
392
      res = eci_impl_fd_read(eci_rep->cmd_read_fd_rep, buf, 1, ECI_READ_TIMEOUT_MS);
 
393
      if (res != 1) {
 
394
        ECI_DEBUG_1("(ecasoundc_sa) fork() of %s FAILED!\n", ecasound_exec);
 
395
        eci_impl_free_parser(eci_rep);
 
396
        free(eci_rep);
 
397
        eci_rep = NULL;
 
398
      }
 
399
      else {
 
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 ++;
 
404
      
 
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);
 
410
          free(eci_rep);
 
411
          eci_rep = NULL;
 
412
        }
 
413
      }
 
414
    }
 
415
  }
 
416
 
 
417
  return (eci_handle_t)eci_rep;
 
418
}
 
419
 
 
420
/**
 
421
 * Checks whether ECI is ready for use.
 
422
 *
 
423
 * @return non-zero if ready, zero otherwise
 
424
 */
 
425
int eci_ready(void)
 
426
{
 
427
  return eci_ready_r(static_eci_rep);
 
428
}
 
429
 
 
430
/**
 
431
 * Checks whether ECI is ready for use.
 
432
 *
 
433
 * @return non-zero if ready, zero otherwise
 
434
 */
 
435
int eci_ready_r(eci_handle_t ptr)
 
436
{
 
437
  struct eci_internal* eci_rep = (struct eci_internal*)ptr;
 
438
 
 
439
  if (!ptr)
 
440
    return 0;
 
441
 
 
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)
 
445
    return 0;
 
446
      
 
447
  return 1;
 
448
}
 
449
 
 
450
/**
 
451
 * Frees all resources.
 
452
 */
 
453
void eci_cleanup(void)
 
454
{
 
455
  if (static_eci_rep != NULL) {
 
456
    eci_cleanup_r(static_eci_rep);
 
457
    static_eci_rep = NULL;
 
458
  }
 
459
}
 
460
 
 
461
/**
 
462
 * Frees all resources.
 
463
 */
 
464
void eci_cleanup_r(eci_handle_t ptr)
 
465
{
 
466
  struct eci_internal* eci_rep = (struct eci_internal*)ptr;
 
467
  ssize_t resread = 1, respoll;
 
468
  char buf[1];
 
469
  struct pollfd fds[1];
 
470
 
 
471
  eci_impl_check_handle(eci_rep);
 
472
 
 
473
  ECI_DEBUG("\n(ecasoundc_sa) requesting to terminatte ecasound process.\n");
 
474
 
 
475
  write(eci_rep->cmd_write_fd_rep, "quit\n", strlen("quit\n"));
 
476
  eci_rep->commands_counter_rep++;
 
477
  
 
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
 
482
   */
 
483
 
 
484
  ECI_DEBUG_1("\n(ecasoundc_sa) cleaning up. waiting for grandchild ecasound process %d.\n", eci_rep->pid_of_child_rep);
 
485
  
 
486
  while (resread > 0) {
 
487
    fds[0].fd = eci_rep->cmd_read_fd_rep;
 
488
    fds[0].events = POLLIN;
 
489
    fds[0].revents = 0;
 
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)
 
494
      resread = -2;
 
495
    
 
496
    ECI_DEBUG_3("(ecasoundc_sa) waiting for ecasound, poll=%d, read=%d, revents=0x%02x)\n", respoll, resread, fds[0].revents);
 
497
  }
 
498
  
 
499
  ECI_DEBUG("(ecasoundc_sa) child exited\n");
 
500
 
 
501
  if (eci_rep != 0) {
 
502
    /* close descriptors */
 
503
    close(eci_rep->cmd_read_fd_rep);
 
504
    close(eci_rep->cmd_write_fd_rep);
 
505
 
 
506
    /* free lists of strings, if any */
 
507
    eci_impl_clean_last_values(eci_rep->parser_repp);
 
508
 
 
509
    eci_impl_free_parser(eci_rep);
 
510
    free(eci_rep);
 
511
  }
 
512
}
 
513
 
 
514
/* ---------------------------------------------------------------------
 
515
 * Issuing EIAM commands 
 
516
 */
 
517
 
 
518
/**
 
519
 * Sends a command to the ecasound engine. See ecasound-iam(5) for
 
520
 * more info.
 
521
 */
 
522
void eci_command(const char* command) { eci_command_r(static_eci_rep, command); }
 
523
 
 
524
/**
 
525
 * Sends a command to the ecasound engine. See ecasound-iam(5) for
 
526
 * more info.
 
527
 */
 
528
void eci_command_r(eci_handle_t ptr, const char* command)
 
529
{
 
530
  struct eci_internal* eci_rep = (struct eci_internal*)ptr;
 
531
  int timeout = ECI_READ_RETVAL_TIMEOUT_MS;
 
532
 
 
533
  eci_impl_check_handle(eci_rep);
 
534
 
 
535
  if (eci_ready_r(ptr) == 0) {
 
536
    ECI_DEBUG("(ecasoundc_sa) not ready, unable to process commands\n");
 
537
    return;
 
538
  }
 
539
 
 
540
  ECI_DEBUG_2("(ecasoundc_sa) writing command '%s' (cmd-counter=%d).\n", 
 
541
              command, eci_rep->commands_counter_rep + 1);
 
542
 
 
543
  memcpy(eci_rep->last_command_repp, command, ECI_MAX_LAST_COMMAND_SIZE);
 
544
 
 
545
  eci_impl_clean_last_values(eci_rep->parser_repp);
 
546
 
 
547
  write(eci_rep->cmd_write_fd_rep, command, strlen(command));
 
548
  write(eci_rep->cmd_write_fd_rep, "\n", 1);
 
549
 
 
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");
 
553
    timeout = -1;
 
554
  }
 
555
 
 
556
  eci_rep->commands_counter_rep++;
 
557
    
 
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;
 
562
  }
 
563
  
 
564
  if (eci_rep->commands_counter_rep >=
 
565
      eci_rep->parser_repp->last_counter_rep) {
 
566
    eci_impl_read_return_value(eci_rep, timeout);
 
567
  }
 
568
 
 
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);
 
571
  
 
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;
 
576
  }
 
577
}
 
578
 
 
579
/** 
 
580
 * A specialized version of 'eci_command()' taking a double value
 
581
 * as the 2nd argument.
 
582
 */
 
583
void eci_command_float_arg(const char* command, double arg) { eci_command_float_arg_r(static_eci_rep, command, arg); }
 
584
 
 
585
/** 
 
586
 * A specialized version of 'eci_command()' taking a double value
 
587
 * as the 2nd argument.
 
588
 */
 
589
void eci_command_float_arg_r(eci_handle_t ptr, const char* command, double arg)
 
590
{
 
591
  struct eci_internal* eci_rep = (struct eci_internal*)ptr;
 
592
 
 
593
  eci_impl_check_handle(eci_rep);
 
594
 
 
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);
 
597
}
 
598
 
 
599
/* ---------------------------------------------------------------------
 
600
 * Getting return values 
 
601
 */
 
602
 
 
603
/**
 
604
 * Returns the number of strings returned by the 
 
605
 * last ECI command.
 
606
 */
 
607
int eci_last_string_list_count(void) { return(eci_last_string_list_count_r(static_eci_rep)); }
 
608
 
 
609
/**
 
610
 * Returns the number of strings returned by the 
 
611
 * last ECI command.
 
612
 */
 
613
int eci_last_string_list_count_r(eci_handle_t ptr)
 
614
{
 
615
  struct eci_internal* eci_rep = (struct eci_internal*)ptr;
 
616
  struct eci_los_list* i;
 
617
  int count = 0;
 
618
 
 
619
  eci_impl_check_handle(eci_rep);
 
620
 
 
621
  for(i = eci_rep->parser_repp->last_los_repp; 
 
622
      i != NULL; 
 
623
      i = i->next_repp) {
 
624
    ++count;
 
625
  }
 
626
 
 
627
  return count;
 
628
}
 
629
 
 
630
/**
 
631
 * Returns the nth item of the list containing 
 
632
 * strings returned by the last ECI command.
 
633
 *
 
634
 * require:
 
635
 *  n >= 0 && n < eci_last_string_list_count()
 
636
 */
 
637
const char* eci_last_string_list_item(int n) { return(eci_last_string_list_item_r(static_eci_rep, n)); }
 
638
 
 
639
/**
 
640
 * Returns the nth item of the list containing 
 
641
 * strings returned by the last ECI command.
 
642
 *
 
643
 * require:
 
644
 *  n >= 0 && n < eci_last_string_list_count()
 
645
 */
 
646
const char* eci_last_string_list_item_r(eci_handle_t ptr, int n)
 
647
{
 
648
  struct eci_internal* eci_rep = (struct eci_internal*)ptr;
 
649
  struct eci_los_list* i;
 
650
  int count = 0;
 
651
 
 
652
  eci_impl_check_handle(eci_rep);
 
653
 
 
654
  for(i = eci_rep->parser_repp->last_los_repp;  
 
655
      i != NULL; 
 
656
      i = i->next_repp) {
 
657
    if (count++ == n) {
 
658
      return i->data_repp.d;
 
659
    }
 
660
  }
 
661
 
 
662
  return NULL;
 
663
}
 
664
 
 
665
const char* eci_last_string(void) { return(eci_last_string_r(static_eci_rep)); }
 
666
 
 
667
const char* eci_last_string_r(eci_handle_t ptr)
 
668
{
 
669
  struct eci_internal* eci_rep = (struct eci_internal*)ptr;
 
670
 
 
671
  eci_impl_check_handle(eci_rep);
 
672
 
 
673
  return eci_rep->parser_repp->last_s_repp.d;
 
674
}
 
675
 
 
676
double eci_last_float(void) { return(eci_last_float_r(static_eci_rep)); }
 
677
 
 
678
double eci_last_float_r(eci_handle_t ptr)
 
679
{
 
680
  struct eci_internal* eci_rep = (struct eci_internal*)ptr;
 
681
 
 
682
  eci_impl_check_handle(eci_rep);
 
683
 
 
684
  return eci_rep->parser_repp->last_f_rep;
 
685
}
 
686
 
 
687
int eci_last_integer(void) { return(eci_last_integer_r(static_eci_rep)); }
 
688
 
 
689
int eci_last_integer_r(eci_handle_t ptr)
 
690
{
 
691
  struct eci_internal* eci_rep = (struct eci_internal*)ptr;
 
692
 
 
693
  eci_impl_check_handle(eci_rep);
 
694
 
 
695
  return eci_rep->parser_repp->last_i_rep;
 
696
}
 
697
 
 
698
long int eci_last_long_integer(void) { return(eci_last_long_integer_r(static_eci_rep)); }
 
699
 
 
700
long int eci_last_long_integer_r(eci_handle_t ptr)
 
701
{
 
702
  struct eci_internal* eci_rep = (struct eci_internal*)ptr;
 
703
 
 
704
  eci_impl_check_handle(eci_rep);
 
705
 
 
706
  return eci_rep->parser_repp->last_li_rep;
 
707
}
 
708
 
 
709
/**
 
710
 * Returns pointer to a null-terminated string containing 
 
711
 * information about the last occured error.
 
712
 */
 
713
const char* eci_last_error(void) { return(eci_last_error_r(static_eci_rep)); }
 
714
 
 
715
/**
 
716
 * Returns pointer to a null-terminated string containing 
 
717
 * information about the last occured error.
 
718
 */
 
719
const char* eci_last_error_r(eci_handle_t ptr)
 
720
{
 
721
  struct eci_internal* eci_rep = (struct eci_internal*)ptr;
 
722
 
 
723
  eci_impl_check_handle(eci_rep);
 
724
  
 
725
  return eci_rep->parser_repp->last_error_repp.d;
 
726
}
 
727
 
 
728
 
 
729
const char* eci_last_type(void) { return(eci_last_type_r(static_eci_rep)); }
 
730
 
 
731
const char* eci_last_type_r(eci_handle_t ptr)
 
732
{
 
733
  struct eci_internal* eci_rep = (struct eci_internal*)ptr;
 
734
 
 
735
  eci_impl_check_handle(eci_rep);
 
736
 
 
737
  return eci_rep->parser_repp->last_type_repp;
 
738
}
 
739
 
 
740
/**
 
741
 * Whether an error has occured?
 
742
 *
 
743
 * @return zero if not in error state
 
744
 */
 
745
int eci_error(void) { return(eci_error_r(static_eci_rep)); }
 
746
 
 
747
/**
 
748
 * Whether an error has occured?
 
749
 *
 
750
 * @return zero if not in error state
 
751
 */
 
752
int eci_error_r(eci_handle_t ptr)
 
753
 
754
  struct eci_internal* eci_rep = (struct eci_internal*)ptr;
 
755
  int res;
 
756
 
 
757
  eci_impl_check_handle(eci_rep);
 
758
 
 
759
  if (eci_ready_r(ptr) == 0) {
 
760
    ECI_DEBUG("(ecasoundc_sa) not ready, raising an error\n");
 
761
    return 1;
 
762
  }
 
763
 
 
764
  if (eci_rep->parser_repp->sync_lost_rep == true) {
 
765
    ECI_DEBUG("(ecasoundc_sa) sync lost, raising an error\n");
 
766
    return 1;
 
767
  }
 
768
 
 
769
  res = (eci_rep->parser_repp->last_type_repp[0] == 'e') ? 1 : 0;
 
770
 
 
771
  ECI_DEBUG_1("(ecasoundc_sa) checking for error, returning %d", res);
 
772
 
 
773
  return res;
 
774
}
 
775
 
 
776
/* --------------------------------------------------------------------- 
 
777
 * Events 
 
778
 */
 
779
 
 
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); }
 
786
 
 
787
/* --------------------------------------------------------------------- 
 
788
 * Implementation of static functions
 
789
 */
 
790
 
 
791
static void eci_string_add(eci_string *dst, int at, char const *src, int len);
 
792
 
 
793
/**
 
794
 * Clears the string contents.
 
795
 *
 
796
 * @post eci_string_len(str)==0
 
797
 * @post strlen(str->d)==0
 
798
 */
 
799
static void eci_string_clear(eci_string *str)
 
800
{
 
801
  DBC_CHECK(str);
 
802
  str->slen = 0;
 
803
  if (str->size == 0) 
 
804
    eci_string_add(str, 0, NULL, 0);
 
805
  else
 
806
    str->d[0] = 0;
 
807
  DBC_CHECK(str->d[0] == 0);
 
808
}
 
809
 
 
810
/**
 
811
 * Initializes the string object for use.
 
812
 * This must only be called after initial 
 
813
 * object allocation.
 
814
 */
 
815
static void eci_string_init(eci_string *str)
 
816
{
 
817
  DBC_CHECK(str);
 
818
  str->slen = 0;
 
819
  str->size = 0;
 
820
  str->d = 0;
 
821
}
 
822
 
 
823
static void eci_string_free(eci_string *str)
 
824
{
 
825
  DBC_CHECK(str);
 
826
  free(str->d);
 
827
  str->size = 0;
 
828
  str->slen = 0;
 
829
}
 
830
 
 
831
/**
 
832
 * Returns the string length.
 
833
 */
 
834
static int eci_string_len(eci_string *str)
 
835
{
 
836
  DBC_CHECK(str);
 
837
  return str->slen;
 
838
}
 
839
 
 
840
/**
 
841
 * Adds 'len' octets from buffer 'src' to the string
 
842
 * at position 'at' (position 0 being the first character).
 
843
 */
 
844
static void eci_string_add(eci_string *dst, int at, char const *src, int len)
 
845
{
 
846
  int space_needed = at + len + 1;
 
847
 
 
848
  DBC_CHECK(dst);
 
849
 
 
850
  if (space_needed > dst->size) {
 
851
    int newsize = 
 
852
      dst->size ? dst->size * 2 : ECI_INI_STRING_SIZE;
 
853
    char *newbuf;
 
854
    while (space_needed > newsize) {
 
855
      newsize *= 2;
 
856
    }
 
857
    assert(newsize <= ECI_MAX_DYN_ALLOC_SIZE);
 
858
    newbuf = realloc(dst->d, newsize);
 
859
    assert(newbuf);
 
860
    dst->size = newsize;
 
861
    dst->d = newbuf;
 
862
  }
 
863
  
 
864
  DBC_CHECK(space_needed <= dst->size);
 
865
 
 
866
  memcpy(&dst->d[at], src, len);
 
867
  dst->d[at + len] = 0;
 
868
}
 
869
 
 
870
static void eci_impl_check_handle(struct eci_internal* eci_rep)
 
871
{
 
872
  if (eci_rep == NULL) {
 
873
    fprintf(stderr, "%s", eci_str_null_handle);
 
874
    DBC_CHECK(eci_rep != NULL);
 
875
    exit(-1);
 
876
  }
 
877
}
 
878
 
 
879
static void eci_impl_free_parser(struct eci_internal* eci_rep)
 
880
{
 
881
  DBC_CHECK(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;
 
887
}
 
888
 
 
889
static void eci_impl_clean_last_values(struct eci_parser* parser)
 
890
{
 
891
  DBC_CHECK(parser != 0);
 
892
 
 
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);
 
900
}
 
901
 
 
902
static void eci_impl_dump_parser_state(eci_handle_t ptr, const char* message)
 
903
{
 
904
  struct eci_internal* eci_rep = (struct eci_internal*)ptr;
 
905
 
 
906
  fprintf(stderr, "\n(ecasoundc_sa) Error='%s', cmd='%s' last_error='%s' cmd_cnt=%d last_cnt=%d.\n", 
 
907
          message,
 
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);
 
912
}
 
913
 
 
914
 
 
915
/**
 
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.
 
920
 */
 
921
static ssize_t eci_impl_fd_read(int fd, void *buf, size_t count, int timeout)
 
922
{
 
923
  int nfds = 1;
 
924
  struct pollfd ufds;
 
925
  ssize_t rescount = 0;
 
926
  int ret;
 
927
 
 
928
  ufds.fd = fd;
 
929
  ufds.events = POLLIN | POLLPRI;
 
930
  ufds.revents = 0;
 
931
  
 
932
  ret = poll(&ufds, nfds, timeout);
 
933
  if (ret > 0) {
 
934
    if (ufds.revents & POLLIN ||
 
935
        ufds.revents & POLLPRI) {
 
936
      rescount = read(fd, buf, count);
 
937
    }
 
938
  }
 
939
  else if (ret == 0) {
 
940
    /* timeout */
 
941
    rescount = -1;
 
942
  }
 
943
  return rescount;
 
944
}
 
945
 
 
946
static const char* eci_impl_get_ecasound_path(void)
 
947
{
 
948
  const char* result = getenv("ECASOUND");
 
949
 
 
950
  if (result == NULL) {
 
951
    fprintf(stderr, "%s", eci_str_no_ecasound_env);
 
952
    result = "ecasound";
 
953
  }
 
954
 
 
955
  return result;
 
956
}
 
957
 
 
958
 
 
959
static struct eci_los_list *eci_impl_los_list_add_item(struct eci_los_list* head, char* stmp, int len)
 
960
{
 
961
  struct eci_los_list* i = head;
 
962
  struct eci_los_list* last = NULL;
 
963
  
 
964
  /* find end of list */
 
965
  while(i != NULL) {
 
966
    last = i;
 
967
    i = i->next_repp;
 
968
  }
 
969
 
 
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;
 
974
  
 
975
  /* ECI_DEBUG_3("(ecasoundc_sa) adding item '%s' to los list; head=%p, i=%p\n", stmp, (void*)head, (void*)i); */
 
976
 
 
977
  /* created a new list, return the new item */
 
978
  if (head == NULL) 
 
979
    return i;
 
980
 
 
981
  /* return the old head */
 
982
  return head;
 
983
}
 
984
 
 
985
struct eci_los_list *eci_impl_los_list_alloc_item(void)
 
986
{
 
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);
 
993
 
 
994
  return item;
 
995
}
 
996
 
 
997
static void eci_impl_los_list_clear(struct eci_los_list *ptr)
 
998
{
 
999
  struct eci_los_list *i = ptr;
 
1000
 
 
1001
  ECI_DEBUG_1("(ecasoundc_sa) clearing list, i=%p\n", (void*)i);
 
1002
 
 
1003
  while(i != NULL) {
 
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);
 
1007
    free(i);
 
1008
    i = next;
 
1009
  }
 
1010
}
 
1011
 
 
1012
static void eci_impl_read_return_value(struct eci_internal* eci_rep, int timeout)
 
1013
{
 
1014
  char* raw_buffer = eci_rep->raw_buffer_repp;
 
1015
  int attempts = 0;
 
1016
 
 
1017
  DBC_CHECK(eci_rep->commands_counter_rep >=
 
1018
            eci_rep->parser_repp->last_counter_rep);
 
1019
 
 
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);
 
1022
    if (res > 0) {
 
1023
      int n;
 
1024
 
 
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); */
 
1027
 
 
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]); */
 
1032
      }
 
1033
 
 
1034
      if (eci_rep->commands_counter_rep ==
 
1035
          eci_rep->parser_repp->last_counter_rep) break;
 
1036
 
 
1037
      /* read return values until the correct one is found */
 
1038
    }
 
1039
    else {
 
1040
      if (res < 0) {
 
1041
        ECI_DEBUG_1("(ecasoundc_sa) timeout when reading return values (attempts=%d)!\n", attempts);
 
1042
        eci_rep->parser_repp->sync_lost_rep = true;
 
1043
        break;
 
1044
      }
 
1045
    }
 
1046
    ++attempts;
 
1047
  }
 
1048
 
 
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;
 
1053
  }
 
1054
}
 
1055
 
 
1056
/**
 
1057
 * Sets the last 'list of strings' values.
 
1058
 *
 
1059
 * @pre parser != 0
 
1060
 * @pre parser->state_rep == ECI_STATE_COMMON_LF_3
 
1061
 */
 
1062
static void eci_impl_set_last_los_value(struct eci_parser* parser)
 
1063
{
 
1064
  struct eci_los_list* i = parser->last_los_repp;
 
1065
  int quoteflag = 0, m = 0, n;
 
1066
  eci_string stmp;
 
1067
  eci_string_init(&stmp);
 
1068
 
 
1069
  DBC_CHECK(parser != 0);
 
1070
  DBC_CHECK(parser->state_rep == ECI_STATE_COMMON_LF_3);
 
1071
 
 
1072
  ECI_DEBUG_2("(ecasoundc_sa) parsing a list '%s' (count=%d)\n", parser->buffer_rep.d, parser->buffer_current_rep);
 
1073
 
 
1074
  eci_impl_los_list_clear(i);
 
1075
  parser->last_los_repp = NULL;
 
1076
 
 
1077
  for(n = 0; n < parser->buffer_current_rep && n < parser->msgsize_rep; n++) {
 
1078
    char c = parser->buffer_rep.d[n];
 
1079
 
 
1080
    if (c == '\"') {
 
1081
      quoteflag = !quoteflag;
 
1082
    }
 
1083
    else if (c == '\\') {
 
1084
      n++;
 
1085
      eci_string_add(&stmp, m++, &parser->buffer_rep.d[n], 1);
 
1086
    }
 
1087
    else if (c != ',' || quoteflag == 1) {
 
1088
      eci_string_add(&stmp, m++, &parser->buffer_rep.d[n], 1);
 
1089
    }
 
1090
    else {
 
1091
      if (m == 0) continue;
 
1092
      i = eci_impl_los_list_add_item(i, stmp.d, m);
 
1093
      m = 0;
 
1094
    }
 
1095
  }
 
1096
  if (m > 0) {
 
1097
    i = eci_impl_los_list_add_item(i, stmp.d, m);
 
1098
  }
 
1099
 
 
1100
  parser->last_los_repp = i;
 
1101
 
 
1102
  eci_string_free(&stmp);
 
1103
}
 
1104
 
 
1105
/**
 
1106
 * Sets the 'last value' fields in the given 'parser'
 
1107
 * object.
 
1108
 *
 
1109
 * @pre parser != 0
 
1110
 * @pre parser->state_rep == ECI_STATE_COMMON_LF_3
 
1111
 */
 
1112
static void eci_impl_set_last_values(struct eci_parser* parser)
 
1113
{
 
1114
  DBC_CHECK(parser != 0);
 
1115
  DBC_CHECK(parser->state_rep == ECI_STATE_COMMON_LF_3);
 
1116
 
 
1117
  switch(parser->last_type_repp[0])
 
1118
    {
 
1119
    case 's':
 
1120
      eci_string_add(&parser->last_s_repp, 0, parser->buffer_rep.d, parser->buffer_current_rep);
 
1121
      break;
 
1122
 
 
1123
    case 'S':
 
1124
      eci_impl_set_last_los_value(parser);
 
1125
      break;
 
1126
 
 
1127
    case 'i':
 
1128
      parser->last_i_rep = atoi(parser->buffer_rep.d);
 
1129
      break;
 
1130
 
 
1131
    case 'l':
 
1132
      parser->last_li_rep = atol(parser->buffer_rep.d);
 
1133
      break;
 
1134
 
 
1135
    case 'f':
 
1136
      parser->last_f_rep = atof(parser->buffer_rep.d);
 
1137
      break;
 
1138
 
 
1139
    case 'e':
 
1140
      eci_string_add(&parser->last_error_repp, 0, parser->buffer_rep.d, parser->buffer_current_rep);
 
1141
      break;
 
1142
 
 
1143
    default: {}
 
1144
 
 
1145
    }
 
1146
}
 
1147
 
 
1148
static void eci_impl_update_state(struct eci_parser* parser, char c)
 
1149
{
 
1150
  switch(parser->state_rep)
 
1151
    {
 
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;
 
1158
      }
 
1159
      else {
 
1160
        parser->token_phase_rep = ECI_TOKEN_PHASE_NONE;
 
1161
      }
 
1162
      break;
 
1163
 
 
1164
    case ECI_STATE_LOGLEVEL:
 
1165
      if (c == ' ') {
 
1166
        parser->loglevel_rep = atoi(parser->buffer_rep.d);
 
1167
 
 
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;
 
1171
        }
 
1172
        else {
 
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;
 
1175
        }
 
1176
          
 
1177
        parser->state_rep = ECI_STATE_MSGSIZE;
 
1178
        parser->token_phase_rep =  ECI_TOKEN_PHASE_NONE;
 
1179
      }
 
1180
      else if (c < 0x30 && c > 0x39) {
 
1181
        parser->state_rep = ECI_STATE_SEEK_TO_LF;
 
1182
      }
 
1183
 
 
1184
      break;
 
1185
 
 
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)) {
 
1189
 
 
1190
        parser->msgsize_rep = atoi(parser->buffer_rep.d);
 
1191
 
 
1192
        /* ECI_DEBUG_3("(ecasoundc_sa) found msgsize '%s' (i=%d,len=%d).\n", parser->buffer_repp, parser->msgsize_rep, parser->buffer_current_rep); */
 
1193
 
 
1194
        if (parser->state_msg_rep == ECI_STATE_MSG_GEN) {
 
1195
          parser->state_rep = ECI_STATE_COMMON_LF_1;
 
1196
        }
 
1197
        else {
 
1198
          parser->state_rep = ECI_STATE_RET_TYPE;
 
1199
        }
 
1200
 
 
1201
        parser->token_phase_rep =  ECI_TOKEN_PHASE_NONE;
 
1202
  
 
1203
      }
 
1204
      else if (c < 0x30 && c > 0x39) {
 
1205
        parser->state_rep = ECI_STATE_SEEK_TO_LF;
 
1206
      }
 
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);
 
1211
      }
 
1212
      break;
 
1213
 
 
1214
    case ECI_STATE_COMMON_CR_1: 
 
1215
      if (c == 0x0d) 
 
1216
        parser->state_rep = ECI_STATE_COMMON_LF_1;
 
1217
      else
 
1218
        parser->state_rep = ECI_STATE_INIT;
 
1219
      break;
 
1220
 
 
1221
    case ECI_STATE_COMMON_LF_1:
 
1222
      if (c == 0x0a) {
 
1223
        parser->state_rep = ECI_STATE_COMMON_CONTENT;
 
1224
      }
 
1225
      else
 
1226
        parser->state_rep = ECI_STATE_INIT;
 
1227
      break;
 
1228
 
 
1229
    case ECI_STATE_RET_TYPE:
 
1230
      if (c == 0x0d) {
 
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);
 
1234
 
 
1235
        memcpy(parser->last_type_repp, parser->buffer_rep.d, len);
 
1236
        parser->last_type_repp[len] = 0;
 
1237
        
 
1238
        ECI_DEBUG_2("(ecasoundc_sa) found rettype '%s' (len=%d)\n", parser->last_type_repp, parser->buffer_current_rep);
 
1239
 
 
1240
        parser->state_rep = ECI_STATE_COMMON_LF_1;
 
1241
        parser->token_phase_rep =  ECI_TOKEN_PHASE_NONE;
 
1242
 
 
1243
      }
 
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);
 
1248
      }
 
1249
 
 
1250
      break;
 
1251
 
 
1252
    case ECI_STATE_COMMON_CONTENT:
 
1253
      if (c == 0x0d) {
 
1254
        /* parse return type */
 
1255
        /* set 'parser->last_xxx_yyy' */
 
1256
 
 
1257
        /* handle empty content */
 
1258
        if (parser->msgsize_rep == 0) 
 
1259
          eci_string_clear(&parser->buffer_rep);
 
1260
 
 
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)
 
1263
          ECI_DEBUG(".\n");
 
1264
        else
 
1265
          ECI_DEBUG_1(" type='%s'.\n", parser->last_type_repp);
 
1266
 
 
1267
        parser->state_rep = ECI_STATE_COMMON_LF_2;
 
1268
        parser->token_phase_rep =  ECI_TOKEN_PHASE_VALIDATE;
 
1269
 
 
1270
      }
 
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);
 
1275
      }
 
1276
      break;
 
1277
 
 
1278
    case ECI_STATE_COMMON_CR_2:
 
1279
      if (c == 0x0d)
 
1280
        parser->state_rep = ECI_STATE_COMMON_LF_2; 
 
1281
      else
 
1282
        parser->state_rep = ECI_STATE_COMMON_CONTENT;
 
1283
      break;
 
1284
        
 
1285
    case ECI_STATE_COMMON_LF_2:
 
1286
      if (c == 0x0a)
 
1287
        parser->state_rep = ECI_STATE_COMMON_CR_3; 
 
1288
      else
 
1289
        parser->state_rep = ECI_STATE_COMMON_CONTENT;
 
1290
      break;
 
1291
 
 
1292
    case ECI_STATE_COMMON_CR_3:
 
1293
      if (c == 0x0d)
 
1294
        parser->state_rep = ECI_STATE_COMMON_LF_3; 
 
1295
      else
 
1296
        parser->state_rep = ECI_STATE_COMMON_CONTENT;
 
1297
      break;
 
1298
 
 
1299
    case ECI_STATE_COMMON_LF_3:
 
1300
      if (c == 0x0a) {
 
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++;
 
1305
        }
 
1306
        else {
 
1307
          ECI_DEBUG_1("(ecasoundc_sa) gen-content validated: <<<%s>>>\n", parser->buffer_rep.d);
 
1308
        }
 
1309
        parser->state_rep = ECI_STATE_INIT; 
 
1310
      }
 
1311
      else
 
1312
        parser->state_rep = ECI_STATE_COMMON_CONTENT;
 
1313
      break;
 
1314
 
 
1315
    case ECI_STATE_SEEK_TO_LF: 
 
1316
      if (c == 0x0a) {
 
1317
        parser->token_phase_rep = ECI_TOKEN_PHASE_NONE;
 
1318
        parser->state_rep = ECI_STATE_INIT;
 
1319
      }
 
1320
      break;
 
1321
 
 
1322
    default: {}
 
1323
 
 
1324
    } /* end of switch() */
 
1325
 
 
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;
 
1329
  }
 
1330
 
 
1331
  //ECI_DEBUG_2("(ecasoundc_sa) parser buf contents: '%s' (cur=%d)\n.", parser->buffer_rep.d, parser->buffer_current_rep);
 
1332
}