Coverage Report

Created: 2026-08-13 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/espeak-ng/src/libespeak-ng/espeak_command.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2007, Gilles Casse <gcasse@oralux.org>
3
 * Copyright (C) 2013-2016 Reece H. Dunn
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, see: <http://www.gnu.org/licenses/>.
17
 */
18
19
#include "config.h"
20
21
#include <assert.h>
22
#include <stdlib.h>
23
#include <string.h>
24
#include <wchar.h>
25
26
#include <espeak-ng/espeak_ng.h>
27
28
#include "espeak_command.h"
29
30
#if USE_ASYNC
31
32
static unsigned int my_current_text_id = 0;
33
34
t_espeak_command *create_espeak_text(const void *text, size_t size, unsigned int position, espeak_POSITION_TYPE position_type, unsigned int end_position, unsigned int flags, void *user_data)
35
0
{
36
0
  if (!text || !size)
37
0
    return NULL;
38
39
0
  void *a_text = NULL;
40
0
  t_espeak_text *data = NULL;
41
42
0
  t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
43
0
  if (!a_command)
44
0
    return NULL;
45
46
0
  a_text = malloc(size+1);
47
0
  if (!a_text) {
48
0
    free(a_command);
49
0
    return NULL;
50
0
  }
51
0
  memcpy(a_text, text, size);
52
53
0
  a_command->type = ET_TEXT;
54
0
  a_command->state = CS_UNDEFINED;
55
0
  data = &(a_command->u.my_text);
56
0
  data->unique_identifier = ++my_current_text_id;
57
0
  data->text = a_text;
58
0
  data->position = position;
59
0
  data->position_type = position_type;
60
0
  data->end_position = end_position;
61
0
  data->flags = flags;
62
0
  data->user_data = user_data;
63
64
0
  return a_command;
65
0
}
66
67
t_espeak_command *create_espeak_terminated_msg(unsigned int unique_identifier, void *user_data)
68
0
{
69
0
  t_espeak_terminated_msg *data = NULL;
70
0
  t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
71
0
  if (!a_command)
72
0
    return NULL;
73
74
0
  a_command->type = ET_TERMINATED_MSG;
75
0
  a_command->state = CS_UNDEFINED;
76
0
  data = &(a_command->u.my_terminated_msg);
77
0
  data->unique_identifier = unique_identifier;
78
0
  data->user_data = user_data;
79
80
0
  return a_command;
81
0
}
82
83
t_espeak_command *create_espeak_mark(const void *text, size_t size, const char *index_mark, unsigned int end_position, unsigned int flags, void *user_data)
84
0
{
85
0
  if (!text || !size || !index_mark)
86
0
    return NULL;
87
88
0
  void *a_text = NULL;
89
0
  char *a_index_mark = NULL;
90
0
  t_espeak_mark *data = NULL;
91
92
0
  t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
93
0
  if (!a_command)
94
0
    return NULL;
95
96
0
  a_text = malloc(size);
97
0
  if (!a_text) {
98
0
    free(a_command);
99
0
    return NULL;
100
0
  }
101
0
  memcpy(a_text, text, size);
102
103
0
  a_index_mark = strdup(index_mark);
104
105
0
  a_command->type = ET_MARK;
106
0
  a_command->state = CS_UNDEFINED;
107
0
  data = &(a_command->u.my_mark);
108
0
  data->unique_identifier = ++my_current_text_id;
109
0
  data->text = a_text;
110
0
  data->index_mark = a_index_mark;
111
0
  data->end_position = end_position;
112
0
  data->flags = flags;
113
0
  data->user_data = user_data;
114
115
0
  return a_command;
116
0
}
117
118
t_espeak_command *create_espeak_key(const char *key_name, void *user_data)
119
0
{
120
0
  if (!key_name)
121
0
    return NULL;
122
123
0
  t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
124
0
  if (!a_command)
125
0
    return NULL;
126
127
0
  a_command->type = ET_KEY;
128
0
  a_command->state = CS_UNDEFINED;
129
0
  a_command->u.my_key.user_data = user_data;
130
0
  a_command->u.my_key.unique_identifier = ++my_current_text_id;
131
0
  a_command->u.my_key.key_name = strdup(key_name);
132
133
0
  return a_command;
134
0
}
135
136
t_espeak_command *create_espeak_char(wchar_t character, void *user_data)
137
0
{
138
0
  t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
139
0
  if (!a_command)
140
0
    return NULL;
141
142
0
  a_command->type = ET_CHAR;
143
0
  a_command->state = CS_UNDEFINED;
144
0
  a_command->u.my_char.user_data = user_data;
145
0
  a_command->u.my_char.unique_identifier = ++my_current_text_id;
146
0
  a_command->u.my_char.character = character;
147
148
0
  return a_command;
149
0
}
150
151
t_espeak_command *create_espeak_parameter(espeak_PARAMETER parameter, int value, int relative)
152
0
{
153
0
  t_espeak_parameter *data = NULL;
154
155
0
  t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
156
0
  if (!a_command)
157
0
    return NULL;
158
159
0
  a_command->type = ET_PARAMETER;
160
0
  a_command->state = CS_UNDEFINED;
161
0
  data = &(a_command->u.my_param);
162
0
  data->parameter = parameter;
163
0
  data->value = value;
164
0
  data->relative = relative;
165
166
0
  return a_command;
167
0
}
168
169
t_espeak_command *create_espeak_punctuation_list(const wchar_t *punctlist)
170
0
{
171
0
  if (!punctlist)
172
0
    return NULL;
173
174
0
  t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
175
0
  if (!a_command)
176
0
    return NULL;
177
178
0
  a_command->type = ET_PUNCTUATION_LIST;
179
0
  a_command->state = CS_UNDEFINED;
180
181
0
  size_t len = (wcslen(punctlist) + 1)*sizeof(wchar_t);
182
0
  wchar_t *a_list = (wchar_t *)malloc(len);
183
0
  if (a_list == NULL) {
184
0
    free(a_command);
185
0
    return NULL;
186
0
  }
187
0
  memcpy(a_list, punctlist, len);
188
0
  a_command->u.my_punctuation_list = a_list;
189
190
0
  return a_command;
191
0
}
192
193
t_espeak_command *create_espeak_voice_name(const char *name)
194
0
{
195
0
  if (!name)
196
0
    return NULL;
197
198
0
  t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
199
0
  if (!a_command)
200
0
    return NULL;
201
202
0
  a_command->type = ET_VOICE_NAME;
203
0
  a_command->state = CS_UNDEFINED;
204
0
  a_command->u.my_voice_name = strdup(name);
205
206
0
  return a_command;
207
0
}
208
209
t_espeak_command *create_espeak_voice_spec(espeak_VOICE *voice)
210
0
{
211
0
  if (!voice)
212
0
    return NULL;
213
214
0
  t_espeak_command *a_command = (t_espeak_command *)malloc(sizeof(t_espeak_command));
215
0
  if (!a_command)
216
0
    return NULL;
217
218
0
  a_command->type = ET_VOICE_SPEC;
219
0
  a_command->state = CS_UNDEFINED;
220
221
0
  espeak_VOICE *data = &(a_command->u.my_voice_spec);
222
0
  memcpy(data, voice, sizeof(espeak_VOICE));
223
224
0
  if (voice->name)
225
0
    data->name = strdup(voice->name);
226
227
0
  if (voice->languages)
228
0
    data->languages = strdup(voice->languages);
229
230
0
  if (voice->identifier)
231
0
    data->identifier = strdup(voice->identifier);
232
233
0
  return a_command;
234
0
}
235
236
int delete_espeak_command(t_espeak_command *the_command)
237
0
{
238
0
  int a_status = 0;
239
0
  if (the_command) {
240
0
    switch (the_command->type)
241
0
    {
242
0
    case ET_TEXT:
243
0
      if (the_command->u.my_text.text)
244
0
        free(the_command->u.my_text.text);
245
0
      break;
246
0
    case ET_MARK:
247
0
      if (the_command->u.my_mark.text)
248
0
        free(the_command->u.my_mark.text);
249
0
      if (the_command->u.my_mark.index_mark)
250
0
        free((void *)(the_command->u.my_mark.index_mark));
251
0
      break;
252
0
    case ET_TERMINATED_MSG:
253
0
    {
254
      // if the terminated msg is pending,
255
      // it must be processed here for informing the calling program
256
      // that its message is finished.
257
      // This can be important for cleaning the related user data.
258
0
      t_espeak_terminated_msg *data = &(the_command->u.my_terminated_msg);
259
0
      if (the_command->state == CS_PENDING) {
260
0
        the_command->state = CS_PROCESSED;
261
0
        sync_espeak_terminated_msg(data->unique_identifier, data->user_data);
262
0
      }
263
0
    }
264
0
      break;
265
0
    case ET_KEY:
266
0
      if (the_command->u.my_key.key_name)
267
0
        free((void *)(the_command->u.my_key.key_name));
268
0
      break;
269
0
    case ET_CHAR:
270
0
    case ET_PARAMETER:
271
      // No allocation
272
0
      break;
273
0
    case ET_PUNCTUATION_LIST:
274
0
      if (the_command->u.my_punctuation_list)
275
0
        free((void *)(the_command->u.my_punctuation_list));
276
0
      break;
277
0
    case ET_VOICE_NAME:
278
0
      if (the_command->u.my_voice_name)
279
0
        free((void *)(the_command->u.my_voice_name));
280
0
      break;
281
0
    case ET_VOICE_SPEC:
282
0
    {
283
0
      espeak_VOICE *data = &(the_command->u.my_voice_spec);
284
285
0
      if (data->name)
286
0
        free((void *)data->name);
287
288
0
      if (data->languages)
289
0
        free((void *)data->languages);
290
291
0
      if (data->identifier)
292
0
        free((void *)data->identifier);
293
0
    }
294
0
      break;
295
0
    default:
296
0
      assert(0);
297
0
    }
298
0
    free(the_command);
299
0
    a_status = 1;
300
0
  }
301
0
  return a_status;
302
0
}
303
304
void process_espeak_command(t_espeak_command *the_command)
305
0
{
306
0
  if (the_command == NULL)
307
0
    return;
308
309
0
  the_command->state = CS_PROCESSED;
310
311
0
  switch (the_command->type)
312
0
  {
313
0
  case ET_TEXT:
314
0
  {
315
0
    t_espeak_text *data = &(the_command->u.my_text);
316
0
    sync_espeak_Synth(data->unique_identifier, data->text,
317
0
                      data->position, data->position_type,
318
0
                      data->end_position, data->flags, data->user_data);
319
0
  }
320
0
    break;
321
0
  case ET_MARK:
322
0
  {
323
0
    t_espeak_mark *data = &(the_command->u.my_mark);
324
0
    sync_espeak_Synth_Mark(data->unique_identifier, data->text,
325
0
                           data->index_mark, data->end_position, data->flags,
326
0
                           data->user_data);
327
0
  }
328
0
    break;
329
0
  case ET_TERMINATED_MSG:
330
0
  {
331
0
    t_espeak_terminated_msg *data = &(the_command->u.my_terminated_msg);
332
0
    sync_espeak_terminated_msg(data->unique_identifier, data->user_data);
333
0
  }
334
0
    break;
335
0
  case ET_KEY:
336
0
  {
337
0
    const char *data = the_command->u.my_key.key_name;
338
0
    sync_espeak_Key(data);
339
0
  }
340
0
    break;
341
0
  case ET_CHAR:
342
0
  {
343
0
    const wchar_t data = the_command->u.my_char.character;
344
0
    sync_espeak_Char(data);
345
0
  }
346
0
    break;
347
0
  case ET_PARAMETER:
348
0
  {
349
0
    t_espeak_parameter *data = &(the_command->u.my_param);
350
0
    SetParameter(data->parameter, data->value, data->relative);
351
0
  }
352
0
    break;
353
0
  case ET_PUNCTUATION_LIST:
354
0
  {
355
0
    const wchar_t *data = the_command->u.my_punctuation_list;
356
0
    sync_espeak_SetPunctuationList(data);
357
0
  }
358
0
    break;
359
0
  case ET_VOICE_NAME:
360
0
  {
361
0
    const char *data = the_command->u.my_voice_name;
362
0
    espeak_SetVoiceByName(data);
363
0
  }
364
0
    break;
365
0
  case ET_VOICE_SPEC:
366
0
  {
367
0
    espeak_VOICE *data = &(the_command->u.my_voice_spec);
368
0
    espeak_SetVoiceByProperties(data);
369
0
  }
370
0
    break;
371
0
  default:
372
0
    assert(0);
373
0
    break;
374
0
  }
375
0
}
376
377
#endif